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`.  The new `DM` reproduces the configuration
102:   of the source, but is not yet setup, so that the user can then define only the ways that the new `DM` should differ
103:   (by, e.g., refinement or repartitioning).  The source `DM` is also set as the adaptivity source `DM` of the new `DM` (see
104:   `DMForestSetAdaptivityForest()`).

106:   Collective

108:   Input Parameters:
109: + dm - the source `DM` object
110: - comm - the communicator for the new `DM` (this communicator is currently ignored, but is present so that `DMForestTemplate()` can be used within `DMCoarsen()`)

112:   Output Parameter:
113: . tdm - the new `DM` object

115:   Level: intermediate

117: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`
118: @*/
119: PetscErrorCode DMForestTemplate(DM dm, MPI_Comm comm, DM *tdm)
120: {
121:   DM_Forest                 *forest = (DM_Forest *)dm->data;
122:   DMType                     type;
123:   DM                         base;
124:   DMForestTopology           topology;
125:   MatType                    mtype;
126:   PetscInt                   dim, overlap, ref, factor;
127:   DMForestAdaptivityStrategy strat;
128:   void                      *ctx;
129:   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
130:   void *mapCtx;

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

163:     PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
164:     PetscCall(DMSetPeriodicity(*tdm, maxCell, Lstart, L));
165:   }
166:   PetscCall(DMGetMatType(dm, &mtype));
167:   PetscCall(DMSetMatType(*tdm, mtype));
168:   PetscFunctionReturn(PETSC_SUCCESS);
169: }

171: static PetscErrorCode DMInitialize_Forest(DM dm);

173: PETSC_EXTERN PetscErrorCode DMClone_Forest(DM dm, DM *newdm)
174: {
175:   DM_Forest  *forest = (DM_Forest *)dm->data;
176:   const char *type;

178:   PetscFunctionBegin;
179:   forest->refct++;
180:   (*newdm)->data = forest;
181:   PetscCall(PetscObjectGetType((PetscObject)dm, &type));
182:   PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, type));
183:   PetscCall(DMInitialize_Forest(*newdm));
184:   PetscFunctionReturn(PETSC_SUCCESS);
185: }

187: static PetscErrorCode DMDestroy_Forest(DM dm)
188: {
189:   DM_Forest *forest = (DM_Forest *)dm->data;

191:   PetscFunctionBegin;
192:   if (--forest->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
193:   if (forest->destroy) PetscCall((*forest->destroy)(dm));
194:   PetscCall(PetscSFDestroy(&forest->cellSF));
195:   PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
196:   PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
197:   PetscCall(DMLabelDestroy(&forest->adaptLabel));
198:   PetscCall(PetscFree(forest->adaptStrategy));
199:   PetscCall(DMDestroy(&forest->base));
200:   PetscCall(DMDestroy(&forest->adapt));
201:   PetscCall(PetscFree(forest->topology));
202:   PetscCall(PetscFree(forest));
203:   PetscFunctionReturn(PETSC_SUCCESS);
204: }

206: /*@C
207:   DMForestSetTopology - Set the topology of a `DMFOREST` during the pre-setup phase.  The topology is a string (e.g.
208:   "cube", "shell") and can be interpreted by subtypes of `DMFOREST`) to construct the base DM of a forest during
209:   `DMSetUp()`.

211:   Logically collectiv

213:   Input parameters:
214: + dm - the forest
215: - topology - the topology of the forest

217:   Level: intermediate

219: .seealso: `DM`, `DMFOREST`, `DMForestGetTopology()`, `DMForestSetBaseDM()`
220: @*/
221: PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology)
222: {
223:   DM_Forest *forest = (DM_Forest *)dm->data;

225:   PetscFunctionBegin;
227:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the topology after setup");
228:   PetscCall(PetscFree(forest->topology));
229:   PetscCall(PetscStrallocpy((const char *)topology, (char **)&forest->topology));
230:   PetscFunctionReturn(PETSC_SUCCESS);
231: }

233: /*@C
234:   DMForestGetTopology - Get a string describing the topology of a `DMFOREST`.

236:   Not Collective

238:   Input parameter:
239: . dm - the forest

241:   Output parameter:
242: . topology - the topology of the forest (e.g., 'cube', 'shell')

244:   Level: intermediate

246: .seealso: `DM`, `DMFOREST`, `DMForestSetTopology()`
247: @*/
248: PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology)
249: {
250:   DM_Forest *forest = (DM_Forest *)dm->data;

252:   PetscFunctionBegin;
255:   *topology = forest->topology;
256:   PetscFunctionReturn(PETSC_SUCCESS);
257: }

259: /*@
260:   DMForestSetBaseDM - During the pre-setup phase, set the `DM` that defines the base mesh of a `DMFOREST` forest.  The
261:   forest will be hierarchically refined from the base, and all refinements/coarsenings of the forest will share its
262:   base.  In general, two forest must share a base to be comparable, to do things like construct interpolators.

264:   Logically Collective

266:   Input Parameters:
267: + dm - the forest
268: - base - the base `DM` of the forest

270:   Level: intermediate

272:   Note:
273:     Currently the base `DM` must be a `DMPLEX`

275: .seealso: `DM`, `DMFOREST`, `DMForestGetBaseDM()`
276: @*/
277: PetscErrorCode DMForestSetBaseDM(DM dm, DM base)
278: {
279:   DM_Forest *forest = (DM_Forest *)dm->data;
280:   PetscInt   dim, dimEmbed;

282:   PetscFunctionBegin;
284:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the base after setup");
285:   PetscCall(PetscObjectReference((PetscObject)base));
286:   PetscCall(DMDestroy(&forest->base));
287:   forest->base = base;
288:   if (base) {
289:     const PetscReal *maxCell, *Lstart, *L;

292:     PetscCall(DMGetDimension(base, &dim));
293:     PetscCall(DMSetDimension(dm, dim));
294:     PetscCall(DMGetCoordinateDim(base, &dimEmbed));
295:     PetscCall(DMSetCoordinateDim(dm, dimEmbed));
296:     PetscCall(DMGetPeriodicity(base, &maxCell, &Lstart, &L));
297:     PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
298:   } else PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
299:   PetscFunctionReturn(PETSC_SUCCESS);
300: }

302: /*@
303:   DMForestGetBaseDM - Get the base DM of a DMForest forest.  The forest will be hierarchically refined from the base,
304:   and all refinements/coarsenings of the forest will share its base.  In general, two forest must share a base to be
305:   comparable, to do things like construct interpolators.

307:   Not Collective

309:   Input Parameter:
310: . dm - the forest

312:   Output Parameter:
313: . base - the base DM of the forest

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

318:   Level: intermediate

320: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()`
321: @*/
322: PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
323: {
324:   DM_Forest *forest = (DM_Forest *)dm->data;

326:   PetscFunctionBegin;
329:   *base = forest->base;
330:   PetscFunctionReturn(PETSC_SUCCESS);
331: }

333: PetscErrorCode DMForestSetBaseCoordinateMapping(DM dm, PetscErrorCode (*func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx)
334: {
335:   DM_Forest *forest = (DM_Forest *)dm->data;

337:   PetscFunctionBegin;
339:   forest->mapcoordinates    = func;
340:   forest->mapcoordinatesctx = ctx;
341:   PetscFunctionReturn(PETSC_SUCCESS);
342: }

344: PetscErrorCode DMForestGetBaseCoordinateMapping(DM dm, PetscErrorCode (**func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx)
345: {
346:   DM_Forest *forest = (DM_Forest *)dm->data;

348:   PetscFunctionBegin;
350:   if (func) *func = forest->mapcoordinates;
351:   if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
352:   PetscFunctionReturn(PETSC_SUCCESS);
353: }

355: /*@
356:   DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the current forest will be
357:   adapted (e.g., the current forest will be refined/coarsened/repartitioned from it) in `DMSetUp()`.  Usually not needed
358:   by users directly: `DMForestTemplate()` constructs a new forest to be adapted from an old forest and calls this
359:   routine.

361:   Logically Collective

363:   Input Parameters:
364: + dm - the new forest, which will be constructed from adapt
365: - adapt - the old forest

367:   Level: intermediate

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

373: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
374: @*/
375: PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
376: {
377:   DM_Forest *forest, *adaptForest, *oldAdaptForest;
378:   DM         oldAdapt;
379:   PetscBool  isForest;

381:   PetscFunctionBegin;
384:   PetscCall(DMIsForest(dm, &isForest));
385:   if (!isForest) PetscFunctionReturn(PETSC_SUCCESS);
386:   PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
387:   forest = (DM_Forest *)dm->data;
388:   PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt));
389:   adaptForest    = (DM_Forest *)(adapt ? adapt->data : NULL);
390:   oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
391:   if (adaptForest != oldAdaptForest) {
392:     PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
393:     PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
394:     if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm));
395:   }
396:   switch (forest->adaptPurpose) {
397:   case DM_ADAPT_DETERMINE:
398:     PetscCall(PetscObjectReference((PetscObject)adapt));
399:     PetscCall(DMDestroy(&(forest->adapt)));
400:     forest->adapt = adapt;
401:     break;
402:   case DM_ADAPT_REFINE:
403:     PetscCall(DMSetCoarseDM(dm, adapt));
404:     break;
405:   case DM_ADAPT_COARSEN:
406:   case DM_ADAPT_COARSEN_LAST:
407:     PetscCall(DMSetFineDM(dm, adapt));
408:     break;
409:   default:
410:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
411:   }
412:   PetscFunctionReturn(PETSC_SUCCESS);
413: }

415: /*@
416:   DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.

418:   Not Collective

420:   Input Parameter:
421: . dm - the forest

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

426:   Level: intermediate

428: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
429: @*/
430: PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
431: {
432:   DM_Forest *forest;

434:   PetscFunctionBegin;
436:   forest = (DM_Forest *)dm->data;
437:   switch (forest->adaptPurpose) {
438:   case DM_ADAPT_DETERMINE:
439:     *adapt = forest->adapt;
440:     break;
441:   case DM_ADAPT_REFINE:
442:     PetscCall(DMGetCoarseDM(dm, adapt));
443:     break;
444:   case DM_ADAPT_COARSEN:
445:   case DM_ADAPT_COARSEN_LAST:
446:     PetscCall(DMGetFineDM(dm, adapt));
447:     break;
448:   default:
449:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
450:   }
451:   PetscFunctionReturn(PETSC_SUCCESS);
452: }

454: /*@
455:   DMForestSetAdaptivityPurpose - During the pre-setup phase, set whether the current `DM` is being adapted from its
456:   source (set with `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening
457:   (`DM_ADAPT_COARSEN`), or undefined (`DM_ADAPT_DETERMINE`).  This only matters for the purposes of reference counting:
458:   during `DMDestroy()`, cyclic references can be found between `DM`s only if the cyclic reference is due to a fine/coarse
459:   relationship (see `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and the user does
460:   not maintain a reference to the post-adaptation forest (i.e., the one created by `DMForestTemplate()`), then this can
461:   cause a memory leak.  This method is used by subtypes of `DMFOREST` when automatically constructing mesh hierarchies.

463:   Logically Collective

465:   Input Parameters:
466: + dm - the forest
467: - purpose - the adaptivity purpose

469:   Level: advanced

471: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
472: @*/
473: PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
474: {
475:   DM_Forest *forest;

477:   PetscFunctionBegin;
478:   forest = (DM_Forest *)dm->data;
479:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
480:   if (purpose != forest->adaptPurpose) {
481:     DM adapt;

483:     PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
484:     PetscCall(PetscObjectReference((PetscObject)adapt));
485:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));

487:     forest->adaptPurpose = purpose;

489:     PetscCall(DMForestSetAdaptivityForest(dm, adapt));
490:     PetscCall(DMDestroy(&adapt));
491:   }
492:   PetscFunctionReturn(PETSC_SUCCESS);
493: }

495: /*@
496:   DMForestGetAdaptivityPurpose - Get whether the current `DM` is being adapted from its source (set with
497:   `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening (`DM_ADAPT_COARSEN`),
498:   coarsening only the last level (`DM_ADAPT_COARSEN_LAST`) or undefined (`DM_ADAPT_DETERMINE`).
499:   This only matters for the purposes of reference counting: during `DMDestroy()`, cyclic
500:   references can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship (see
501:   `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and the user does not maintain a
502:   reference to the post-adaptation forest (i.e., the one created by `DMForestTemplate()`), then this can cause a memory
503:   leak.  This method is used by subtypes of `DMFOREST` when automatically constructing mesh hierarchies.

505:   Not Collective

507:   Input Parameter:
508: . dm - the forest

510:   Output Parameter:
511: . purpose - the adaptivity purpose

513:   Level: advanced

515: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
516: @*/
517: PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
518: {
519:   DM_Forest *forest;

521:   PetscFunctionBegin;
522:   forest   = (DM_Forest *)dm->data;
523:   *purpose = forest->adaptPurpose;
524:   PetscFunctionReturn(PETSC_SUCCESS);
525: }

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

531:   Logically Collective

533:   Input Parameters:
534: + dm - the forest
535: - adjDim - default 0 (i.e., vertices determine adjacency)

537:   Level: intermediate

539: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
540: @*/
541: PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
542: {
543:   PetscInt   dim;
544:   DM_Forest *forest = (DM_Forest *)dm->data;

546:   PetscFunctionBegin;
548:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup");
549:   PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim);
550:   PetscCall(DMGetDimension(dm, &dim));
551:   PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim);
552:   forest->adjDim = adjDim;
553:   PetscFunctionReturn(PETSC_SUCCESS);
554: }

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

560:   Logically Collective

562:   Input Parameters:
563: + dm - the forest
564: - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices

566:   Level: intermediate

568: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
569: @*/
570: PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
571: {
572:   PetscInt dim;

574:   PetscFunctionBegin;
576:   PetscCall(DMGetDimension(dm, &dim));
577:   PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim));
578:   PetscFunctionReturn(PETSC_SUCCESS);
579: }

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

585:   Not Collective

587:   Input Parameter:
588: . dm - the forest

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

593:   Level: intermediate

595: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
596: @*/
597: PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim)
598: {
599:   DM_Forest *forest = (DM_Forest *)dm->data;

601:   PetscFunctionBegin;
604:   *adjDim = forest->adjDim;
605:   PetscFunctionReturn(PETSC_SUCCESS);
606: }

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

612:   Not Collective

614:   Input Parameter:
615: . dm - the forest

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

620:   Level: intermediate

622: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
623: @*/
624: PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
625: {
626:   DM_Forest *forest = (DM_Forest *)dm->data;
627:   PetscInt   dim;

629:   PetscFunctionBegin;
632:   PetscCall(DMGetDimension(dm, &dim));
633:   *adjCodim = dim - forest->adjDim;
634:   PetscFunctionReturn(PETSC_SUCCESS);
635: }

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

642:   Logically Collective

644:   Input Parameters:
645: + dm - the forest
646: - overlap - default 0

648:   Level: intermediate

650: .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
651: @*/
652: PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
653: {
654:   DM_Forest *forest = (DM_Forest *)dm->data;

656:   PetscFunctionBegin;
658:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup");
659:   PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap);
660:   forest->overlap = overlap;
661:   PetscFunctionReturn(PETSC_SUCCESS);
662: }

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

668:   Not Collective

670:   Input Parameter:
671: . dm - the forest

673:   Output Parameter:
674: . overlap - default 0

676:   Level: intermediate

678: .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
679: @*/
680: PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
681: {
682:   DM_Forest *forest = (DM_Forest *)dm->data;

684:   PetscFunctionBegin;
687:   *overlap = forest->overlap;
688:   PetscFunctionReturn(PETSC_SUCCESS);
689: }

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

696:   Logically Collective

698:   Input Parameters:
699: + dm - the forest
700: - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

702:   Level: intermediate

704: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
705: @*/
706: PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
707: {
708:   DM_Forest *forest = (DM_Forest *)dm->data;

710:   PetscFunctionBegin;
712:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the minimum refinement after setup");
713:   forest->minRefinement = minRefinement;
714:   PetscFunctionReturn(PETSC_SUCCESS);
715: }

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

722:   Not Collective

724:   Input Parameter:
725: . dm - the forest

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

730:   Level: intermediate

732: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
733: @*/
734: PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
735: {
736:   DM_Forest *forest = (DM_Forest *)dm->data;

738:   PetscFunctionBegin;
741:   *minRefinement = forest->minRefinement;
742:   PetscFunctionReturn(PETSC_SUCCESS);
743: }

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

749:   Logically Collective

751:   Input Parameters:
752: + dm - the forest
753: - initefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

755:   Level: intermediate

757: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
758: @*/
759: PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement)
760: {
761:   DM_Forest *forest = (DM_Forest *)dm->data;

763:   PetscFunctionBegin;
765:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup");
766:   forest->initRefinement = initRefinement;
767:   PetscFunctionReturn(PETSC_SUCCESS);
768: }

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

774:   Not Collective

776:   Input Parameter:
777: . dm - the forest

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

782:   Level: intermediate

784: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
785: @*/
786: PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement)
787: {
788:   DM_Forest *forest = (DM_Forest *)dm->data;

790:   PetscFunctionBegin;
793:   *initRefinement = forest->initRefinement;
794:   PetscFunctionReturn(PETSC_SUCCESS);
795: }

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

802:   Logically Collective

804:   Input Parameters:
805: + dm - the forest
806: - maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

808:   Level: intermediate

810: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()`
811: @*/
812: PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement)
813: {
814:   DM_Forest *forest = (DM_Forest *)dm->data;

816:   PetscFunctionBegin;
818:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup");
819:   forest->maxRefinement = maxRefinement;
820:   PetscFunctionReturn(PETSC_SUCCESS);
821: }

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

828:   Not Collective

830:   Input Parameter:
831: . dm - the forest

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

836:   Level: intermediate

838: .seealso: `DM`, `DMFOREST`, `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
839: @*/
840: PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement)
841: {
842:   DM_Forest *forest = (DM_Forest *)dm->data;

844:   PetscFunctionBegin;
847:   *maxRefinement = forest->maxRefinement;
848:   PetscFunctionReturn(PETSC_SUCCESS);
849: }

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

854:   Logically Collective

856:   Input Parameters:
857: + dm - the forest
858: - adaptStrategy - default `DMFORESTADAPTALL`

860:   Level: advanced

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

867: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`
868: @*/
869: PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
870: {
871:   DM_Forest *forest = (DM_Forest *)dm->data;

873:   PetscFunctionBegin;
875:   PetscCall(PetscFree(forest->adaptStrategy));
876:   PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy));
877:   PetscFunctionReturn(PETSC_SUCCESS);
878: }

880: /*@C
881:   DMForestSetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.

883:   Not Collective

885:   Input Parameter:
886: . dm - the forest

888:   Output Parameter:
889: . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`)

891:   Level: advanced

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

899: .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()`
900: @*/
901: PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
902: {
903:   DM_Forest *forest = (DM_Forest *)dm->data;

905:   PetscFunctionBegin;
908:   *adaptStrategy = forest->adaptStrategy;
909:   PetscFunctionReturn(PETSC_SUCCESS);
910: }

912: /*@
913:   DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
914:   etc.) was successful.

916:   Collective

918:   Input Parameter:
919: . dm - the post-adaptation forest

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

924:   Level: intermediate

926:   Notes:
927:   `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adpatation
928:   forest.  A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
929:   exceeded the maximum refinement level.

931: .seealso: `DM`, `DMFOREST`
932: @*/
933: PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
934: {
935:   DM_Forest *forest;

937:   PetscFunctionBegin;
939:   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet.");
940:   forest = (DM_Forest *)dm->data;
941:   PetscCall((forest->getadaptivitysuccess)(dm, success));
942:   PetscFunctionReturn(PETSC_SUCCESS);
943: }

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

949:   Logically Collective

951:   Input Parameters:
952: + dm - the post-adaptation forest
953: - computeSF - default `PETSC_TRUE`

955:   Level: advanced

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

960: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
961: @*/
962: PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
963: {
964:   DM_Forest *forest;

966:   PetscFunctionBegin;
968:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called");
969:   forest                 = (DM_Forest *)dm->data;
970:   forest->computeAdaptSF = computeSF;
971:   PetscFunctionReturn(PETSC_SUCCESS);
972: }

974: PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
975: {
976:   DM_Forest *forest;

978:   PetscFunctionBegin;
983:   forest = (DM_Forest *)dmIn->data;
984:   PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented");
985:   PetscCall((forest->transfervec)(dmIn, vecIn, dmOut, vecOut, useBCs, time));
986:   PetscFunctionReturn(PETSC_SUCCESS);
987: }

989: PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
990: {
991:   DM_Forest *forest;

993:   PetscFunctionBegin;
997:   forest = (DM_Forest *)dm->data;
998:   PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented");
999:   PetscCall((forest->transfervecfrombase)(dm, vecIn, vecOut));
1000:   PetscFunctionReturn(PETSC_SUCCESS);
1001: }

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

1008:   Not Collective

1010:   Input Parameter:
1011: . dm - the post-adaptation forest

1013:   Output Parameter:
1014: . computeSF - default `PETSC_TRUE`

1016:   Level: advanced

1018: .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
1019: @*/
1020: PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
1021: {
1022:   DM_Forest *forest;

1024:   PetscFunctionBegin;
1026:   forest     = (DM_Forest *)dm->data;
1027:   *computeSF = forest->computeAdaptSF;
1028:   PetscFunctionReturn(PETSC_SUCCESS);
1029: }

1031: /*@
1032:   DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the post-adaptation forest.
1033:   Adaptation can be any combination of refinement, coarsening, repartition, and change of overlap, so there may be
1034:   some cells of the pre-adaptation that are parents of post-adaptation cells, and vice versa.  Therefore there are two
1035:   `PetscSF`s: one that relates pre-adaptation coarse cells to post-adaptation fine cells, and one that relates
1036:   pre-adaptation fine cells to post-adaptation coarse cells.

1038:   Not Collective

1040:   Input Parameter:
1041: .  dm - the post-adaptation forest

1043:   Output Parameters:
1044: +  preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
1045: -  coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-

1047:   Level: advanced

1049: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
1050: @*/
1051: PetscErrorCode DMForestGetAdaptivitySF(DM dm, PetscSF *preCoarseToFine, PetscSF *coarseToPreFine)
1052: {
1053:   DM_Forest *forest;

1055:   PetscFunctionBegin;
1057:   PetscCall(DMSetUp(dm));
1058:   forest = (DM_Forest *)dm->data;
1059:   if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
1060:   if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
1061:   PetscFunctionReturn(PETSC_SUCCESS);
1062: }

1064: /*@
1065:   DMForestSetGradeFactor - During the pre-setup phase, set the desired amount of grading in the mesh, e.g. give 2 to
1066:   indicate that the diameter of neighboring cells should differ by at most a factor of 2.  Subtypes of `DMFOREST` may
1067:   only support one particular choice of grading factor.

1069:   Logically Collective

1071:   Input Parameters:
1072: + dm - the forest
1073: - grade - the grading factor

1075:   Level: advanced

1077: .seealso: `DM`, `DMFOREST`, `DMForestGetGradeFactor()`
1078: @*/
1079: PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade)
1080: {
1081:   DM_Forest *forest = (DM_Forest *)dm->data;

1083:   PetscFunctionBegin;
1085:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup");
1086:   forest->gradeFactor = grade;
1087:   PetscFunctionReturn(PETSC_SUCCESS);
1088: }

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

1095:   Not Collective

1097:   Input Parameter:
1098: . dm - the forest

1100:   Output Parameter:
1101: . grade - the grading factor

1103:   Level: advanced

1105: .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()`
1106: @*/
1107: PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
1108: {
1109:   DM_Forest *forest = (DM_Forest *)dm->data;

1111:   PetscFunctionBegin;
1114:   *grade = forest->gradeFactor;
1115:   PetscFunctionReturn(PETSC_SUCCESS);
1116: }

1118: /*@
1119:   DMForestSetCellWeightFactor - During the pre-setup phase, set the factor by which the level of refinement changes
1120:   the cell weight (see `DMForestSetCellWeights()`) when calculating partitions.  The final weight of a cell will be
1121:   (cellWeight) * (weightFactor^refinementLevel).  A factor of 1 indicates that the weight of a cell does not depend on
1122:   its level; a factor of 2, for example, might be appropriate for sub-cycling time-stepping methods, when the
1123:   computation associated with a cell is multiplied by a factor of 2 for each additional level of refinement.

1125:   Logically Collective

1127:   Input Parameters:
1128: + dm - the forest
1129: - weightsFactors - default 1.

1131:   Level: advanced

1133: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()`
1134: @*/
1135: PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor)
1136: {
1137:   DM_Forest *forest = (DM_Forest *)dm->data;

1139:   PetscFunctionBegin;
1141:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup");
1142:   forest->weightsFactor = weightsFactor;
1143:   PetscFunctionReturn(PETSC_SUCCESS);
1144: }

1146: /*@
1147:   DMForestGetCellWeightFactor - Get the factor by which the level of refinement changes the cell weight (see
1148:   `DMForestSetCellWeights()`) when calculating partitions.  The final weight of a cell will be (cellWeight) *
1149:   (weightFactor^refinementLevel).  A factor of 1 indicates that the weight of a cell does not depend on its level; a
1150:   factor of 2, for example, might be appropriate for sub-cycling time-stepping methods, when the computation
1151:   associated with a cell is multiplied by a factor of 2 for each additional level of refinement.

1153:   Not Collective

1155:   Input Parameter:
1156: . dm - the forest

1158:   Output Parameter:
1159: . weightsFactors - default 1.

1161:   Level: advanced

1163: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
1164: @*/
1165: PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
1166: {
1167:   DM_Forest *forest = (DM_Forest *)dm->data;

1169:   PetscFunctionBegin;
1172:   *weightsFactor = forest->weightsFactor;
1173:   PetscFunctionReturn(PETSC_SUCCESS);
1174: }

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

1179:   Not Collective

1181:   Input Parameter:
1182: . dm - the forest

1184:   Output Parameters:
1185: + cStart - the first cell on this process
1186: - cEnd - one after the final cell on this process

1188:   Level: intermediate

1190: .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()`
1191: @*/
1192: PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
1193: {
1194:   DM_Forest *forest = (DM_Forest *)dm->data;

1196:   PetscFunctionBegin;
1200:   if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd));
1201:   *cStart = forest->cStart;
1202:   *cEnd   = forest->cEnd;
1203:   PetscFunctionReturn(PETSC_SUCCESS);
1204: }

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

1209:   Not Collective

1211:   Input Parameter:
1212: . dm - the forest

1214:   Output Parameter:
1215: . cellSF - the `PetscSF`

1217:   Level: intermediate

1219: .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()`
1220: @*/
1221: PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
1222: {
1223:   DM_Forest *forest = (DM_Forest *)dm->data;

1225:   PetscFunctionBegin;
1228:   if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF));
1229:   *cellSF = forest->cellSF;
1230:   PetscFunctionReturn(PETSC_SUCCESS);
1231: }

1233: /*@C
1234:   DMForestSetAdaptivityLabel - During the pre-setup phase, set the label of the pre-adaptation forest (see
1235:   `DMForestGetAdaptivityForest()`) that holds the adaptation flags (refinement, coarsening, or some combination).  The
1236:   interpretation of the label values is up to the subtype of `DMFOREST`, but `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`,
1237:   `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been reserved as choices that should be accepted by all subtypes.

1239:   Logically Collective

1241:   Input Parameters:
1242: - dm - the forest
1243: + adaptLabel - the label in the pre-adaptation forest

1245:   Level: intermediate

1247: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()`
1248: @*/
1249: PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
1250: {
1251:   DM_Forest *forest = (DM_Forest *)dm->data;

1253:   PetscFunctionBegin;
1256:   PetscCall(PetscObjectReference((PetscObject)adaptLabel));
1257:   PetscCall(DMLabelDestroy(&forest->adaptLabel));
1258:   forest->adaptLabel = adaptLabel;
1259:   PetscFunctionReturn(PETSC_SUCCESS);
1260: }

1262: /*@C
1263:   DMForestGetAdaptivityLabel - Get the label of the pre-adaptation forest (see `DMForestGetAdaptivityForest()`) that
1264:   holds the adaptation flags (refinement, coarsening, or some combination).  The interpretation of the label values is
1265:   up to the subtype of `DMFOREST`, but `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have
1266:   been reserved as choices that should be accepted by all subtypes.

1268:   Not Collective

1270:   Input Parameter:
1271: . dm - the forest

1273:   Output Parameter:
1274: . adaptLabel - the name of the label in the pre-adaptation forest

1276:   Level: intermediate

1278: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()`
1279: @*/
1280: PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
1281: {
1282:   DM_Forest *forest = (DM_Forest *)dm->data;

1284:   PetscFunctionBegin;
1286:   *adaptLabel = forest->adaptLabel;
1287:   PetscFunctionReturn(PETSC_SUCCESS);
1288: }

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

1294:   Logically Collective

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

1301:   Level: advanced

1303: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
1304: @*/
1305: PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
1306: {
1307:   DM_Forest *forest = (DM_Forest *)dm->data;
1308:   PetscInt   cStart, cEnd;

1310:   PetscFunctionBegin;
1312:   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
1313:   PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd);
1314:   if (copyMode == PETSC_COPY_VALUES) {
1315:     if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights));
1316:     PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart));
1317:     forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
1318:     PetscFunctionReturn(PETSC_SUCCESS);
1319:   }
1320:   if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights));
1321:   forest->cellWeights         = weights;
1322:   forest->cellWeightsCopyMode = copyMode;
1323:   PetscFunctionReturn(PETSC_SUCCESS);
1324: }

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

1330:   Not Collective

1332:   Input Parameter:
1333: . dm - the forest

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

1338:   Level: advanced

1340: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
1341: @*/
1342: PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
1343: {
1344:   DM_Forest *forest = (DM_Forest *)dm->data;

1346:   PetscFunctionBegin;
1349:   *weights = forest->cellWeights;
1350:   PetscFunctionReturn(PETSC_SUCCESS);
1351: }

1353: /*@
1354:   DMForestSetWeightCapacity - During the pre-setup phase, set the capacity of the current process when repartitioning
1355:   a pre-adaptation forest (see `DMForestGetAdaptivityForest()`).  After partitioning, the ratio of the weight of each
1356:   process's cells to the process's capacity will be roughly equal for all processes.  A capacity of 0 indicates that
1357:   the current process should not have any cells after repartitioning.

1359:   Logically Collective

1361:   Input parameters:
1362: + dm - the forest
1363: - capacity - this process's capacity

1365:   Level: advanced

1367: .seealso `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1368: @*/
1369: PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
1370: {
1371:   DM_Forest *forest = (DM_Forest *)dm->data;

1373:   PetscFunctionBegin;
1375:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup");
1376:   PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity);
1377:   forest->weightCapacity = capacity;
1378:   PetscFunctionReturn(PETSC_SUCCESS);
1379: }

1381: /*@
1382:   DMForestGetWeightCapacity - Set the capacity of the current process when repartitioning a pre-adaptation forest (see
1383:   `DMForestGetAdaptivityForest()`).  After partitioning, the ratio of the weight of each process's cells to the
1384:   process's capacity will be roughly equal for all processes.  A capacity of 0 indicates that the current process
1385:   should not have any cells after repartitioning.

1387:   Not Collective

1389:   Input parameter:
1390: . dm - the forest

1392:   Output parameter:
1393: . capacity - this process's capacity

1395:   Level: advanced

1397: .seealso `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1398: @*/
1399: PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
1400: {
1401:   DM_Forest *forest = (DM_Forest *)dm->data;

1403:   PetscFunctionBegin;
1406:   *capacity = forest->weightCapacity;
1407:   PetscFunctionReturn(PETSC_SUCCESS);
1408: }

1410: PETSC_EXTERN PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems *PetscOptionsObject)
1411: {
1412:   PetscBool                  flg, flg1, flg2, flg3, flg4;
1413:   DMForestTopology           oldTopo;
1414:   char                       stringBuffer[256];
1415:   PetscViewer                viewer;
1416:   PetscViewerFormat          format;
1417:   PetscInt                   adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
1418:   PetscReal                  weightsFactor;
1419:   DMForestAdaptivityStrategy adaptStrategy;

1421:   PetscFunctionBegin;
1422:   PetscCall(DMForestGetTopology(dm, &oldTopo));
1423:   PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
1424:   PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1));
1425:   PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2));
1426:   PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3));
1427:   PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4));
1428:   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}");
1429:   if (flg1) {
1430:     PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer));
1431:     PetscCall(DMForestSetBaseDM(dm, NULL));
1432:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1433:   }
1434:   if (flg2) {
1435:     DM base;

1437:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base));
1438:     PetscCall(PetscViewerPushFormat(viewer, format));
1439:     PetscCall(DMLoad(base, viewer));
1440:     PetscCall(PetscViewerDestroy(&viewer));
1441:     PetscCall(DMForestSetBaseDM(dm, base));
1442:     PetscCall(DMDestroy(&base));
1443:     PetscCall(DMForestSetTopology(dm, NULL));
1444:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1445:   }
1446:   if (flg3) {
1447:     DM coarse;

1449:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse));
1450:     PetscCall(PetscViewerPushFormat(viewer, format));
1451:     PetscCall(DMLoad(coarse, viewer));
1452:     PetscCall(PetscViewerDestroy(&viewer));
1453:     PetscCall(DMForestSetAdaptivityForest(dm, coarse));
1454:     PetscCall(DMDestroy(&coarse));
1455:     PetscCall(DMForestSetTopology(dm, NULL));
1456:     PetscCall(DMForestSetBaseDM(dm, NULL));
1457:   }
1458:   if (flg4) {
1459:     DM fine;

1461:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine));
1462:     PetscCall(PetscViewerPushFormat(viewer, format));
1463:     PetscCall(DMLoad(fine, viewer));
1464:     PetscCall(PetscViewerDestroy(&viewer));
1465:     PetscCall(DMForestSetAdaptivityForest(dm, fine));
1466:     PetscCall(DMDestroy(&fine));
1467:     PetscCall(DMForestSetTopology(dm, NULL));
1468:     PetscCall(DMForestSetBaseDM(dm, NULL));
1469:   }
1470:   PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
1471:   PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0));
1472:   if (flg) {
1473:     PetscCall(DMForestSetAdjacencyDimension(dm, adjDim));
1474:   } else {
1475:     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
1476:     PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1));
1477:     if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim));
1478:   }
1479:   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
1480:   PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0));
1481:   if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap));
1482: #if 0
1483:   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));
1484:   if (flg) {
1485:     PetscCall(DMForestSetMinimumRefinement(dm,minRefinement));
1486:     PetscCall(DMForestSetInitialRefinement(dm,minRefinement));
1487:   }
1488:   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0));
1489:   if (flg) {
1490:     PetscCall(DMForestSetMinimumRefinement(dm,0));
1491:     PetscCall(DMForestSetInitialRefinement(dm,initRefinement));
1492:   }
1493: #endif
1494:   PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement));
1495:   PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0));
1496:   if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement));
1497:   PetscCall(DMForestGetInitialRefinement(dm, &initRefinement));
1498:   PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0));
1499:   if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement));
1500:   PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement));
1501:   PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0));
1502:   if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement));
1503:   PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy));
1504:   PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg));
1505:   if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer));
1506:   PetscCall(DMForestGetGradeFactor(dm, &grade));
1507:   PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0));
1508:   if (flg) PetscCall(DMForestSetGradeFactor(dm, grade));
1509:   PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor));
1510:   PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg));
1511:   if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor));
1512:   PetscOptionsHeadEnd();
1513:   PetscFunctionReturn(PETSC_SUCCESS);
1514: }

1516: PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1517: {
1518:   PetscFunctionBegin;
1519:   if (subdm) PetscCall(DMClone(dm, subdm));
1520:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
1521:   PetscFunctionReturn(PETSC_SUCCESS);
1522: }

1524: PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
1525: {
1526:   DMLabel refine;
1527:   DM      fineDM;

1529:   PetscFunctionBegin;
1530:   PetscCall(DMGetFineDM(dm, &fineDM));
1531:   if (fineDM) {
1532:     PetscCall(PetscObjectReference((PetscObject)fineDM));
1533:     *dmRefined = fineDM;
1534:     PetscFunctionReturn(PETSC_SUCCESS);
1535:   }
1536:   PetscCall(DMForestTemplate(dm, comm, dmRefined));
1537:   PetscCall(DMGetLabel(dm, "refine", &refine));
1538:   if (!refine) {
1539:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine));
1540:     PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE));
1541:   } else PetscCall(PetscObjectReference((PetscObject)refine));
1542:   PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine));
1543:   PetscCall(DMLabelDestroy(&refine));
1544:   PetscFunctionReturn(PETSC_SUCCESS);
1545: }

1547: PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
1548: {
1549:   DMLabel coarsen;
1550:   DM      coarseDM;

1552:   PetscFunctionBegin;
1553:   {
1554:     PetscMPIInt mpiComparison;
1555:     MPI_Comm    dmcomm = PetscObjectComm((PetscObject)dm);

1557:     PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison));
1558:     PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet");
1559:   }
1560:   PetscCall(DMGetCoarseDM(dm, &coarseDM));
1561:   if (coarseDM) {
1562:     PetscCall(PetscObjectReference((PetscObject)coarseDM));
1563:     *dmCoarsened = coarseDM;
1564:     PetscFunctionReturn(PETSC_SUCCESS);
1565:   }
1566:   PetscCall(DMForestTemplate(dm, comm, dmCoarsened));
1567:   PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN));
1568:   PetscCall(DMGetLabel(dm, "coarsen", &coarsen));
1569:   if (!coarsen) {
1570:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
1571:     PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
1572:   } else PetscCall(PetscObjectReference((PetscObject)coarsen));
1573:   PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen));
1574:   PetscCall(DMLabelDestroy(&coarsen));
1575:   PetscFunctionReturn(PETSC_SUCCESS);
1576: }

1578: PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
1579: {
1580:   PetscBool success;

1582:   PetscFunctionBegin;
1583:   PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM));
1584:   PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label));
1585:   PetscCall(DMSetUp(*adaptedDM));
1586:   PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success));
1587:   if (!success) {
1588:     PetscCall(DMDestroy(adaptedDM));
1589:     *adaptedDM = NULL;
1590:   }
1591:   PetscFunctionReturn(PETSC_SUCCESS);
1592: }

1594: static PetscErrorCode DMInitialize_Forest(DM dm)
1595: {
1596:   PetscFunctionBegin;
1597:   PetscCall(PetscMemzero(dm->ops, sizeof(*(dm->ops))));

1599:   dm->ops->clone          = DMClone_Forest;
1600:   dm->ops->setfromoptions = DMSetFromOptions_Forest;
1601:   dm->ops->destroy        = DMDestroy_Forest;
1602:   dm->ops->createsubdm    = DMCreateSubDM_Forest;
1603:   dm->ops->refine         = DMRefine_Forest;
1604:   dm->ops->coarsen        = DMCoarsen_Forest;
1605:   PetscFunctionReturn(PETSC_SUCCESS);
1606: }

1608: /*MC

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

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

1621:   Level: advanced

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

1626: PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
1627: {
1628:   DM_Forest *forest;

1630:   PetscFunctionBegin;
1632:   PetscCall(PetscNew(&forest));
1633:   dm->dim                     = 0;
1634:   dm->data                    = forest;
1635:   forest->refct               = 1;
1636:   forest->data                = NULL;
1637:   forest->topology            = NULL;
1638:   forest->adapt               = NULL;
1639:   forest->base                = NULL;
1640:   forest->adaptPurpose        = DM_ADAPT_DETERMINE;
1641:   forest->adjDim              = PETSC_DEFAULT;
1642:   forest->overlap             = PETSC_DEFAULT;
1643:   forest->minRefinement       = PETSC_DEFAULT;
1644:   forest->maxRefinement       = PETSC_DEFAULT;
1645:   forest->initRefinement      = PETSC_DEFAULT;
1646:   forest->cStart              = PETSC_DETERMINE;
1647:   forest->cEnd                = PETSC_DETERMINE;
1648:   forest->cellSF              = NULL;
1649:   forest->adaptLabel          = NULL;
1650:   forest->gradeFactor         = 2;
1651:   forest->cellWeights         = NULL;
1652:   forest->cellWeightsCopyMode = PETSC_USE_POINTER;
1653:   forest->weightsFactor       = 1.;
1654:   forest->weightCapacity      = 1.;
1655:   PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL));
1656:   PetscCall(DMInitialize_Forest(dm));
1657:   PetscFunctionReturn(PETSC_SUCCESS);
1658: }