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: . tdm - 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 *tdm)
123: {
124:   DM_Forest                 *forest = (DM_Forest *)dm->data;
125:   DMType                     type;
126:   DM                         base;
127:   DMForestTopology           topology;
128:   MatType                    mtype;
129:   PetscInt                   dim, overlap, ref, factor;
130:   DMForestAdaptivityStrategy strat;
131:   void                      *ctx;
132:   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
133:   void *mapCtx;

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

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

174: static PetscErrorCode DMInitialize_Forest(DM dm);

176: PETSC_EXTERN 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:   if (--forest->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
196:   if (forest->destroy) PetscCall((*forest->destroy)(dm));
197:   PetscCall(PetscSFDestroy(&forest->cellSF));
198:   PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
199:   PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
200:   PetscCall(DMLabelDestroy(&forest->adaptLabel));
201:   PetscCall(PetscFree(forest->adaptStrategy));
202:   PetscCall(DMDestroy(&forest->base));
203:   PetscCall(DMDestroy(&forest->adapt));
204:   PetscCall(PetscFree(forest->topology));
205:   PetscCall(PetscFree(forest));
206:   PetscFunctionReturn(PETSC_SUCCESS);
207: }

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

214:   Logically collectiv

216:   Input Parameters:
217: + dm       - the forest
218: - topology - the topology of the forest

220:   Level: intermediate

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

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

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

239:   Not Collective

241:   Input Parameter:
242: . dm - the forest

244:   Output Parameter:
245: . topology - the topology of the forest (e.g., 'cube', 'shell')

247:   Level: intermediate

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

255:   PetscFunctionBegin;
257:   PetscAssertPointer(topology, 2);
258:   *topology = forest->topology;
259:   PetscFunctionReturn(PETSC_SUCCESS);
260: }

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

266:   Logically Collective

268:   Input Parameters:
269: + dm   - the forest
270: - base - the base `DM` of the forest

272:   Level: intermediate

274:   Notes:
275:   The forest will be hierarchically refined from the base, and all refinements/coarsenings of
276:   the forest will share its base.  In general, two forest must share a base to be comparable,
277:   to do things like construct interpolators.

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

281: .seealso: `DM`, `DMFOREST`, `DMForestGetBaseDM()`
282: @*/
283: PetscErrorCode DMForestSetBaseDM(DM dm, DM base)
284: {
285:   DM_Forest *forest = (DM_Forest *)dm->data;
286:   PetscInt   dim, dimEmbed;

288:   PetscFunctionBegin;
290:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the base after setup");
291:   PetscCall(PetscObjectReference((PetscObject)base));
292:   PetscCall(DMDestroy(&forest->base));
293:   forest->base = base;
294:   if (base) {
295:     const PetscReal *maxCell, *Lstart, *L;

298:     PetscCall(DMGetDimension(base, &dim));
299:     PetscCall(DMSetDimension(dm, dim));
300:     PetscCall(DMGetCoordinateDim(base, &dimEmbed));
301:     PetscCall(DMSetCoordinateDim(dm, dimEmbed));
302:     PetscCall(DMGetPeriodicity(base, &maxCell, &Lstart, &L));
303:     PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
304:   } else PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
305:   PetscFunctionReturn(PETSC_SUCCESS);
306: }

308: /*@
309:   DMForestGetBaseDM - Get the base `DM` of a `DMFOREST`

311:   Not Collective

313:   Input Parameter:
314: . dm - the forest

316:   Output Parameter:
317: . base - the base `DM` of the forest

319:   Level: intermediate

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

324:   The forest will be hierarchically refined from the base, and all refinements/coarsenings of
325:   the forest will share its base.  In general, two forest must share a base to be comparable,
326:   to do things like construct interpolators.

328: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()`
329: @*/
330: PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
331: {
332:   DM_Forest *forest = (DM_Forest *)dm->data;

334:   PetscFunctionBegin;
336:   PetscAssertPointer(base, 2);
337:   *base = forest->base;
338:   PetscFunctionReturn(PETSC_SUCCESS);
339: }

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

345:   PetscFunctionBegin;
347:   forest->mapcoordinates    = func;
348:   forest->mapcoordinatesctx = ctx;
349:   PetscFunctionReturn(PETSC_SUCCESS);
350: }

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

356:   PetscFunctionBegin;
358:   if (func) *func = forest->mapcoordinates;
359:   if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
360:   PetscFunctionReturn(PETSC_SUCCESS);
361: }

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

368:   Logically Collective

370:   Input Parameters:
371: + dm    - the new forest, which will be constructed from adapt
372: - adapt - the old forest

374:   Level: intermediate

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

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

384: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
385: @*/
386: PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
387: {
388:   DM_Forest *forest, *adaptForest, *oldAdaptForest;
389:   DM         oldAdapt;
390:   PetscBool  isForest;

392:   PetscFunctionBegin;
395:   PetscCall(DMIsForest(dm, &isForest));
396:   if (!isForest) PetscFunctionReturn(PETSC_SUCCESS);
397:   PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
398:   forest = (DM_Forest *)dm->data;
399:   PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt));
400:   adaptForest    = (DM_Forest *)(adapt ? adapt->data : NULL);
401:   oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
402:   if (adaptForest != oldAdaptForest) {
403:     PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
404:     PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
405:     if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm));
406:   }
407:   switch (forest->adaptPurpose) {
408:   case DM_ADAPT_DETERMINE:
409:     PetscCall(PetscObjectReference((PetscObject)adapt));
410:     PetscCall(DMDestroy(&(forest->adapt)));
411:     forest->adapt = adapt;
412:     break;
413:   case DM_ADAPT_REFINE:
414:     PetscCall(DMSetCoarseDM(dm, adapt));
415:     break;
416:   case DM_ADAPT_COARSEN:
417:   case DM_ADAPT_COARSEN_LAST:
418:     PetscCall(DMSetFineDM(dm, adapt));
419:     break;
420:   default:
421:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
422:   }
423:   PetscFunctionReturn(PETSC_SUCCESS);
424: }

426: /*@
427:   DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.

429:   Not Collective

431:   Input Parameter:
432: . dm - the forest

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

437:   Level: intermediate

439: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
440: @*/
441: PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
442: {
443:   DM_Forest *forest;

445:   PetscFunctionBegin;
447:   forest = (DM_Forest *)dm->data;
448:   switch (forest->adaptPurpose) {
449:   case DM_ADAPT_DETERMINE:
450:     *adapt = forest->adapt;
451:     break;
452:   case DM_ADAPT_REFINE:
453:     PetscCall(DMGetCoarseDM(dm, adapt));
454:     break;
455:   case DM_ADAPT_COARSEN:
456:   case DM_ADAPT_COARSEN_LAST:
457:     PetscCall(DMGetFineDM(dm, adapt));
458:     break;
459:   default:
460:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
461:   }
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

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

470:   Logically Collective

472:   Input Parameters:
473: + dm      - the forest
474: - purpose - the adaptivity purpose

476:   Level: advanced

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

486: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
487: @*/
488: PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
489: {
490:   DM_Forest *forest;

492:   PetscFunctionBegin;
493:   forest = (DM_Forest *)dm->data;
494:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
495:   if (purpose != forest->adaptPurpose) {
496:     DM adapt;

498:     PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
499:     PetscCall(PetscObjectReference((PetscObject)adapt));
500:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));

502:     forest->adaptPurpose = purpose;

504:     PetscCall(DMForestSetAdaptivityForest(dm, adapt));
505:     PetscCall(DMDestroy(&adapt));
506:   }
507:   PetscFunctionReturn(PETSC_SUCCESS);
508: }

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

515:   Not Collective

517:   Input Parameter:
518: . dm - the forest

520:   Output Parameter:
521: . purpose - the adaptivity purpose

523:   Level: advanced

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

533: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
534: @*/
535: PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
536: {
537:   DM_Forest *forest;

539:   PetscFunctionBegin;
540:   forest   = (DM_Forest *)dm->data;
541:   *purpose = forest->adaptPurpose;
542:   PetscFunctionReturn(PETSC_SUCCESS);
543: }

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

549:   Logically Collective

551:   Input Parameters:
552: + dm     - the forest
553: - adjDim - default 0 (i.e., vertices determine adjacency)

555:   Level: intermediate

557: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
558: @*/
559: PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
560: {
561:   PetscInt   dim;
562:   DM_Forest *forest = (DM_Forest *)dm->data;

564:   PetscFunctionBegin;
566:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup");
567:   PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim);
568:   PetscCall(DMGetDimension(dm, &dim));
569:   PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim);
570:   forest->adjDim = adjDim;
571:   PetscFunctionReturn(PETSC_SUCCESS);
572: }

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

578:   Logically Collective

580:   Input Parameters:
581: + dm       - the forest
582: - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices

584:   Level: intermediate

586: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
587: @*/
588: PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
589: {
590:   PetscInt dim;

592:   PetscFunctionBegin;
594:   PetscCall(DMGetDimension(dm, &dim));
595:   PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim));
596:   PetscFunctionReturn(PETSC_SUCCESS);
597: }

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

603:   Not Collective

605:   Input Parameter:
606: . dm - the forest

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

611:   Level: intermediate

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

619:   PetscFunctionBegin;
621:   PetscAssertPointer(adjDim, 2);
622:   *adjDim = forest->adjDim;
623:   PetscFunctionReturn(PETSC_SUCCESS);
624: }

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

630:   Not Collective

632:   Input Parameter:
633: . dm - the forest

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

638:   Level: intermediate

640: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
641: @*/
642: PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
643: {
644:   DM_Forest *forest = (DM_Forest *)dm->data;
645:   PetscInt   dim;

647:   PetscFunctionBegin;
649:   PetscAssertPointer(adjCodim, 2);
650:   PetscCall(DMGetDimension(dm, &dim));
651:   *adjCodim = dim - forest->adjDim;
652:   PetscFunctionReturn(PETSC_SUCCESS);
653: }

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

660:   Logically Collective

662:   Input Parameters:
663: + dm      - the forest
664: - overlap - default 0

666:   Level: intermediate

668: .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
669: @*/
670: PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
671: {
672:   DM_Forest *forest = (DM_Forest *)dm->data;

674:   PetscFunctionBegin;
676:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup");
677:   PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap);
678:   forest->overlap = overlap;
679:   PetscFunctionReturn(PETSC_SUCCESS);
680: }

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

686:   Not Collective

688:   Input Parameter:
689: . dm - the forest

691:   Output Parameter:
692: . overlap - default 0

694:   Level: intermediate

696: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
697: @*/
698: PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
699: {
700:   DM_Forest *forest = (DM_Forest *)dm->data;

702:   PetscFunctionBegin;
704:   PetscAssertPointer(overlap, 2);
705:   *overlap = forest->overlap;
706:   PetscFunctionReturn(PETSC_SUCCESS);
707: }

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

714:   Logically Collective

716:   Input Parameters:
717: + dm            - the forest
718: - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)

720:   Level: intermediate

722: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
723: @*/
724: PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
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 minimum refinement after setup");
731:   forest->minRefinement = minRefinement;
732:   PetscFunctionReturn(PETSC_SUCCESS);
733: }

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

740:   Not Collective

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

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

748:   Level: intermediate

750: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
751: @*/
752: PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
753: {
754:   DM_Forest *forest = (DM_Forest *)dm->data;

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

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

767:   Logically Collective

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

773:   Level: intermediate

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

781:   PetscFunctionBegin;
783:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup");
784:   forest->initRefinement = initRefinement;
785:   PetscFunctionReturn(PETSC_SUCCESS);
786: }

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

792:   Not Collective

794:   Input Parameter:
795: . dm - the forest

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

800:   Level: intermediate

802: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
803: @*/
804: PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement)
805: {
806:   DM_Forest *forest = (DM_Forest *)dm->data;

808:   PetscFunctionBegin;
810:   PetscAssertPointer(initRefinement, 2);
811:   *initRefinement = forest->initRefinement;
812:   PetscFunctionReturn(PETSC_SUCCESS);
813: }

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

820:   Logically Collective

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

826:   Level: intermediate

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

834:   PetscFunctionBegin;
836:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup");
837:   forest->maxRefinement = maxRefinement;
838:   PetscFunctionReturn(PETSC_SUCCESS);
839: }

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

846:   Not Collective

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

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

854:   Level: intermediate

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

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

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

872:   Logically Collective

874:   Input Parameters:
875: + dm            - the forest
876: - adaptStrategy - default `DMFORESTADAPTALL`

878:   Level: advanced

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

885: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`
886: @*/
887: PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
888: {
889:   DM_Forest *forest = (DM_Forest *)dm->data;

891:   PetscFunctionBegin;
893:   PetscCall(PetscFree(forest->adaptStrategy));
894:   PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy));
895:   PetscFunctionReturn(PETSC_SUCCESS);
896: }

898: /*@C
899:   DMForestGetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.

901:   Not Collective

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

906:   Output Parameter:
907: . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`)

909:   Level: advanced

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

917: .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()`
918: @*/
919: PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
920: {
921:   DM_Forest *forest = (DM_Forest *)dm->data;

923:   PetscFunctionBegin;
925:   PetscAssertPointer(adaptStrategy, 2);
926:   *adaptStrategy = forest->adaptStrategy;
927:   PetscFunctionReturn(PETSC_SUCCESS);
928: }

930: /*@
931:   DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
932:   etc.) was successful.

934:   Collective

936:   Input Parameter:
937: . dm - the post-adaptation forest

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

942:   Level: intermediate

944:   Notes:
945:   `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adaptation
946:   forest.  A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
947:   exceeded the maximum refinement level.

949: .seealso: `DM`, `DMFOREST`
950: @*/
951: PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
952: {
953:   DM_Forest *forest;

955:   PetscFunctionBegin;
957:   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet.");
958:   forest = (DM_Forest *)dm->data;
959:   PetscCall((forest->getadaptivitysuccess)(dm, success));
960:   PetscFunctionReturn(PETSC_SUCCESS);
961: }

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

967:   Logically Collective

969:   Input Parameters:
970: + dm        - the post-adaptation forest
971: - computeSF - default `PETSC_TRUE`

973:   Level: advanced

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

978: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
979: @*/
980: PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
981: {
982:   DM_Forest *forest;

984:   PetscFunctionBegin;
986:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called");
987:   forest                 = (DM_Forest *)dm->data;
988:   forest->computeAdaptSF = computeSF;
989:   PetscFunctionReturn(PETSC_SUCCESS);
990: }

992: PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
993: {
994:   DM_Forest *forest;

996:   PetscFunctionBegin;
1001:   forest = (DM_Forest *)dmIn->data;
1002:   PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented");
1003:   PetscCall((forest->transfervec)(dmIn, vecIn, dmOut, vecOut, useBCs, time));
1004:   PetscFunctionReturn(PETSC_SUCCESS);
1005: }

1007: PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
1008: {
1009:   DM_Forest *forest;

1011:   PetscFunctionBegin;
1015:   forest = (DM_Forest *)dm->data;
1016:   PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented");
1017:   PetscCall((forest->transfervecfrombase)(dm, vecIn, vecOut));
1018:   PetscFunctionReturn(PETSC_SUCCESS);
1019: }

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

1026:   Not Collective

1028:   Input Parameter:
1029: . dm - the post-adaptation forest

1031:   Output Parameter:
1032: . computeSF - default `PETSC_TRUE`

1034:   Level: advanced

1036: .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
1037: @*/
1038: PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
1039: {
1040:   DM_Forest *forest;

1042:   PetscFunctionBegin;
1044:   forest     = (DM_Forest *)dm->data;
1045:   *computeSF = forest->computeAdaptSF;
1046:   PetscFunctionReturn(PETSC_SUCCESS);
1047: }

1049: /*@
1050:   DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the
1051:   post-adaptation forest.

1053:   Not Collective

1055:   Input Parameter:
1056: . dm - the post-adaptation forest

1058:   Output Parameters:
1059: + preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
1060: - coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-

1062:   Level: advanced

1064:   Notes:
1065:   Adaptation can be any combination of refinement, coarsening, repartition, and change of
1066:   overlap, so there may be some cells of the pre-adaptation that are parents of post-adaptation
1067:   cells, and vice versa.  Therefore there are two `PetscSF`s: one that relates pre-adaptation
1068:   coarse cells to post-adaptation fine cells, and one that relates pre-adaptation fine cells to
1069:   post-adaptation coarse cells.

1071: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
1072: @*/
1073: PetscErrorCode DMForestGetAdaptivitySF(DM dm, PetscSF *preCoarseToFine, PetscSF *coarseToPreFine)
1074: {
1075:   DM_Forest *forest;

1077:   PetscFunctionBegin;
1079:   PetscCall(DMSetUp(dm));
1080:   forest = (DM_Forest *)dm->data;
1081:   if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
1082:   if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
1083:   PetscFunctionReturn(PETSC_SUCCESS);
1084: }

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

1091:   Logically Collective

1093:   Input Parameters:
1094: + dm    - the forest
1095: - grade - the grading factor

1097:   Level: advanced

1099:   Note:
1100:   Subtypes of `DMFOREST` may only support one particular choice of grading factor.

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

1108:   PetscFunctionBegin;
1110:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup");
1111:   forest->gradeFactor = grade;
1112:   PetscFunctionReturn(PETSC_SUCCESS);
1113: }

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

1120:   Not Collective

1122:   Input Parameter:
1123: . dm - the forest

1125:   Output Parameter:
1126: . grade - the grading factor

1128:   Level: advanced

1130: .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()`
1131: @*/
1132: PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
1133: {
1134:   DM_Forest *forest = (DM_Forest *)dm->data;

1136:   PetscFunctionBegin;
1138:   PetscAssertPointer(grade, 2);
1139:   *grade = forest->gradeFactor;
1140:   PetscFunctionReturn(PETSC_SUCCESS);
1141: }

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

1147:   Logically Collective

1149:   Input Parameters:
1150: + dm            - the forest
1151: - weightsFactor - default 1.

1153:   Level: advanced

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

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

1168:   PetscFunctionBegin;
1170:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup");
1171:   forest->weightsFactor = weightsFactor;
1172:   PetscFunctionReturn(PETSC_SUCCESS);
1173: }

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

1179:   Not Collective

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

1184:   Output Parameter:
1185: . weightsFactor - default 1.

1187:   Level: advanced

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

1196: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
1197: @*/
1198: PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
1199: {
1200:   DM_Forest *forest = (DM_Forest *)dm->data;

1202:   PetscFunctionBegin;
1204:   PetscAssertPointer(weightsFactor, 2);
1205:   *weightsFactor = forest->weightsFactor;
1206:   PetscFunctionReturn(PETSC_SUCCESS);
1207: }

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

1212:   Not Collective

1214:   Input Parameter:
1215: . dm - the forest

1217:   Output Parameters:
1218: + cStart - the first cell on this process
1219: - cEnd   - one after the final cell on this process

1221:   Level: intermediate

1223: .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()`
1224: @*/
1225: PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
1226: {
1227:   DM_Forest *forest = (DM_Forest *)dm->data;

1229:   PetscFunctionBegin;
1231:   PetscAssertPointer(cStart, 2);
1232:   PetscAssertPointer(cEnd, 3);
1233:   if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd));
1234:   *cStart = forest->cStart;
1235:   *cEnd   = forest->cEnd;
1236:   PetscFunctionReturn(PETSC_SUCCESS);
1237: }

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

1242:   Not Collective

1244:   Input Parameter:
1245: . dm - the forest

1247:   Output Parameter:
1248: . cellSF - the `PetscSF`

1250:   Level: intermediate

1252: .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()`
1253: @*/
1254: PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
1255: {
1256:   DM_Forest *forest = (DM_Forest *)dm->data;

1258:   PetscFunctionBegin;
1260:   PetscAssertPointer(cellSF, 2);
1261:   if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF));
1262:   *cellSF = forest->cellSF;
1263:   PetscFunctionReturn(PETSC_SUCCESS);
1264: }

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

1270:   Logically Collective

1272:   Input Parameters:
1273: + dm         - the forest
1274: - adaptLabel - the label in the pre-adaptation forest

1276:   Level: intermediate

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

1283: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()`
1284: @*/
1285: PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
1286: {
1287:   DM_Forest *forest = (DM_Forest *)dm->data;

1289:   PetscFunctionBegin;
1292:   PetscCall(PetscObjectReference((PetscObject)adaptLabel));
1293:   PetscCall(DMLabelDestroy(&forest->adaptLabel));
1294:   forest->adaptLabel = adaptLabel;
1295:   PetscFunctionReturn(PETSC_SUCCESS);
1296: }

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

1302:   Not Collective

1304:   Input Parameter:
1305: . dm - the forest

1307:   Output Parameter:
1308: . adaptLabel - the name of the label in the pre-adaptation forest

1310:   Level: intermediate

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

1317: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()`
1318: @*/
1319: PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
1320: {
1321:   DM_Forest *forest = (DM_Forest *)dm->data;

1323:   PetscFunctionBegin;
1325:   *adaptLabel = forest->adaptLabel;
1326:   PetscFunctionReturn(PETSC_SUCCESS);
1327: }

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

1333:   Logically Collective

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

1340:   Level: advanced

1342: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
1343: @*/
1344: PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
1345: {
1346:   DM_Forest *forest = (DM_Forest *)dm->data;
1347:   PetscInt   cStart, cEnd;

1349:   PetscFunctionBegin;
1351:   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
1352:   PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd);
1353:   if (copyMode == PETSC_COPY_VALUES) {
1354:     if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights));
1355:     PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart));
1356:     forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
1357:     PetscFunctionReturn(PETSC_SUCCESS);
1358:   }
1359:   if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights));
1360:   forest->cellWeights         = weights;
1361:   forest->cellWeightsCopyMode = copyMode;
1362:   PetscFunctionReturn(PETSC_SUCCESS);
1363: }

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

1369:   Not Collective

1371:   Input Parameter:
1372: . dm - the forest

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

1377:   Level: advanced

1379: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
1380: @*/
1381: PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
1382: {
1383:   DM_Forest *forest = (DM_Forest *)dm->data;

1385:   PetscFunctionBegin;
1387:   PetscAssertPointer(weights, 2);
1388:   *weights = forest->cellWeights;
1389:   PetscFunctionReturn(PETSC_SUCCESS);
1390: }

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

1396:   Logically Collective

1398:   Input Parameters:
1399: + dm       - the forest
1400: - capacity - this process's capacity

1402:   Level: advanced

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

1409: .seealso: `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1410: @*/
1411: PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
1412: {
1413:   DM_Forest *forest = (DM_Forest *)dm->data;

1415:   PetscFunctionBegin;
1417:   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup");
1418:   PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity);
1419:   forest->weightCapacity = capacity;
1420:   PetscFunctionReturn(PETSC_SUCCESS);
1421: }

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

1427:   Not Collective

1429:   Input Parameter:
1430: . dm - the forest

1432:   Output Parameter:
1433: . capacity - this process's capacity

1435:   Level: advanced

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

1442: .seealso: `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1443: @*/
1444: PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
1445: {
1446:   DM_Forest *forest = (DM_Forest *)dm->data;

1448:   PetscFunctionBegin;
1450:   PetscAssertPointer(capacity, 2);
1451:   *capacity = forest->weightCapacity;
1452:   PetscFunctionReturn(PETSC_SUCCESS);
1453: }

1455: PETSC_EXTERN PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems *PetscOptionsObject)
1456: {
1457:   PetscBool                  flg, flg1, flg2, flg3, flg4;
1458:   DMForestTopology           oldTopo;
1459:   char                       stringBuffer[256];
1460:   PetscViewer                viewer;
1461:   PetscViewerFormat          format;
1462:   PetscInt                   adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
1463:   PetscReal                  weightsFactor;
1464:   DMForestAdaptivityStrategy adaptStrategy;

1466:   PetscFunctionBegin;
1467:   PetscCall(DMForestGetTopology(dm, &oldTopo));
1468:   PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
1469:   PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1));
1470:   PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2));
1471:   PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3));
1472:   PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4));
1473:   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}");
1474:   if (flg1) {
1475:     PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer));
1476:     PetscCall(DMForestSetBaseDM(dm, NULL));
1477:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1478:   }
1479:   if (flg2) {
1480:     DM base;

1482:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base));
1483:     PetscCall(PetscViewerPushFormat(viewer, format));
1484:     PetscCall(DMLoad(base, viewer));
1485:     PetscCall(PetscViewerDestroy(&viewer));
1486:     PetscCall(DMForestSetBaseDM(dm, base));
1487:     PetscCall(DMDestroy(&base));
1488:     PetscCall(DMForestSetTopology(dm, NULL));
1489:     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1490:   }
1491:   if (flg3) {
1492:     DM coarse;

1494:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse));
1495:     PetscCall(PetscViewerPushFormat(viewer, format));
1496:     PetscCall(DMLoad(coarse, viewer));
1497:     PetscCall(PetscViewerDestroy(&viewer));
1498:     PetscCall(DMForestSetAdaptivityForest(dm, coarse));
1499:     PetscCall(DMDestroy(&coarse));
1500:     PetscCall(DMForestSetTopology(dm, NULL));
1501:     PetscCall(DMForestSetBaseDM(dm, NULL));
1502:   }
1503:   if (flg4) {
1504:     DM fine;

1506:     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine));
1507:     PetscCall(PetscViewerPushFormat(viewer, format));
1508:     PetscCall(DMLoad(fine, viewer));
1509:     PetscCall(PetscViewerDestroy(&viewer));
1510:     PetscCall(DMForestSetAdaptivityForest(dm, fine));
1511:     PetscCall(DMDestroy(&fine));
1512:     PetscCall(DMForestSetTopology(dm, NULL));
1513:     PetscCall(DMForestSetBaseDM(dm, NULL));
1514:   }
1515:   PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
1516:   PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0));
1517:   if (flg) {
1518:     PetscCall(DMForestSetAdjacencyDimension(dm, adjDim));
1519:   } else {
1520:     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
1521:     PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1));
1522:     if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim));
1523:   }
1524:   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
1525:   PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0));
1526:   if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap));
1527: #if 0
1528:   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));
1529:   if (flg) {
1530:     PetscCall(DMForestSetMinimumRefinement(dm,minRefinement));
1531:     PetscCall(DMForestSetInitialRefinement(dm,minRefinement));
1532:   }
1533:   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0));
1534:   if (flg) {
1535:     PetscCall(DMForestSetMinimumRefinement(dm,0));
1536:     PetscCall(DMForestSetInitialRefinement(dm,initRefinement));
1537:   }
1538: #endif
1539:   PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement));
1540:   PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0));
1541:   if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement));
1542:   PetscCall(DMForestGetInitialRefinement(dm, &initRefinement));
1543:   PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0));
1544:   if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement));
1545:   PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement));
1546:   PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0));
1547:   if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement));
1548:   PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy));
1549:   PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg));
1550:   if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer));
1551:   PetscCall(DMForestGetGradeFactor(dm, &grade));
1552:   PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0));
1553:   if (flg) PetscCall(DMForestSetGradeFactor(dm, grade));
1554:   PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor));
1555:   PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg));
1556:   if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor));
1557:   PetscOptionsHeadEnd();
1558:   PetscFunctionReturn(PETSC_SUCCESS);
1559: }

1561: static PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1562: {
1563:   PetscFunctionBegin;
1564:   if (subdm) PetscCall(DMClone(dm, subdm));
1565:   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
1566:   PetscFunctionReturn(PETSC_SUCCESS);
1567: }

1569: static PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
1570: {
1571:   DMLabel refine;
1572:   DM      fineDM;

1574:   PetscFunctionBegin;
1575:   PetscCall(DMGetFineDM(dm, &fineDM));
1576:   if (fineDM) {
1577:     PetscCall(PetscObjectReference((PetscObject)fineDM));
1578:     *dmRefined = fineDM;
1579:     PetscFunctionReturn(PETSC_SUCCESS);
1580:   }
1581:   PetscCall(DMForestTemplate(dm, comm, dmRefined));
1582:   PetscCall(DMGetLabel(dm, "refine", &refine));
1583:   if (!refine) {
1584:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine));
1585:     PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE));
1586:   } else PetscCall(PetscObjectReference((PetscObject)refine));
1587:   PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine));
1588:   PetscCall(DMLabelDestroy(&refine));
1589:   PetscFunctionReturn(PETSC_SUCCESS);
1590: }

1592: static PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
1593: {
1594:   DMLabel coarsen;
1595:   DM      coarseDM;

1597:   PetscFunctionBegin;
1598:   {
1599:     PetscMPIInt mpiComparison;
1600:     MPI_Comm    dmcomm = PetscObjectComm((PetscObject)dm);

1602:     PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison));
1603:     PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet");
1604:   }
1605:   PetscCall(DMGetCoarseDM(dm, &coarseDM));
1606:   if (coarseDM) {
1607:     PetscCall(PetscObjectReference((PetscObject)coarseDM));
1608:     *dmCoarsened = coarseDM;
1609:     PetscFunctionReturn(PETSC_SUCCESS);
1610:   }
1611:   PetscCall(DMForestTemplate(dm, comm, dmCoarsened));
1612:   PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN));
1613:   PetscCall(DMGetLabel(dm, "coarsen", &coarsen));
1614:   if (!coarsen) {
1615:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
1616:     PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
1617:   } else PetscCall(PetscObjectReference((PetscObject)coarsen));
1618:   PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen));
1619:   PetscCall(DMLabelDestroy(&coarsen));
1620:   PetscFunctionReturn(PETSC_SUCCESS);
1621: }

1623: PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
1624: {
1625:   PetscBool success;

1627:   PetscFunctionBegin;
1628:   PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM));
1629:   PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label));
1630:   PetscCall(DMSetUp(*adaptedDM));
1631:   PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success));
1632:   if (!success) {
1633:     PetscCall(DMDestroy(adaptedDM));
1634:     *adaptedDM = NULL;
1635:   }
1636:   PetscFunctionReturn(PETSC_SUCCESS);
1637: }

1639: static PetscErrorCode DMInitialize_Forest(DM dm)
1640: {
1641:   PetscFunctionBegin;
1642:   PetscCall(PetscMemzero(dm->ops, sizeof(*(dm->ops))));

1644:   dm->ops->clone          = DMClone_Forest;
1645:   dm->ops->setfromoptions = DMSetFromOptions_Forest;
1646:   dm->ops->destroy        = DMDestroy_Forest;
1647:   dm->ops->createsubdm    = DMCreateSubDM_Forest;
1648:   dm->ops->refine         = DMRefine_Forest;
1649:   dm->ops->coarsen        = DMCoarsen_Forest;
1650:   PetscFunctionReturn(PETSC_SUCCESS);
1651: }

1653: /*MC

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

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

1666:   Level: advanced

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

1671: PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
1672: {
1673:   DM_Forest *forest;

1675:   PetscFunctionBegin;
1677:   PetscCall(PetscNew(&forest));
1678:   dm->dim                     = 0;
1679:   dm->data                    = forest;
1680:   forest->refct               = 1;
1681:   forest->data                = NULL;
1682:   forest->topology            = NULL;
1683:   forest->adapt               = NULL;
1684:   forest->base                = NULL;
1685:   forest->adaptPurpose        = DM_ADAPT_DETERMINE;
1686:   forest->adjDim              = PETSC_DEFAULT;
1687:   forest->overlap             = PETSC_DEFAULT;
1688:   forest->minRefinement       = PETSC_DEFAULT;
1689:   forest->maxRefinement       = PETSC_DEFAULT;
1690:   forest->initRefinement      = PETSC_DEFAULT;
1691:   forest->cStart              = PETSC_DETERMINE;
1692:   forest->cEnd                = PETSC_DETERMINE;
1693:   forest->cellSF              = NULL;
1694:   forest->adaptLabel          = NULL;
1695:   forest->gradeFactor         = 2;
1696:   forest->cellWeights         = NULL;
1697:   forest->cellWeightsCopyMode = PETSC_USE_POINTER;
1698:   forest->weightsFactor       = 1.;
1699:   forest->weightCapacity      = 1.;
1700:   PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL));
1701:   PetscCall(DMInitialize_Forest(dm));
1702:   PetscFunctionReturn(PETSC_SUCCESS);
1703: }