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:   while (link) {
 22:     oldLink = link;
 23:     PetscFree(oldLink->name);
 24:     link = oldLink->next;
 25:     PetscFree(oldLink);
 26:   }
 27:   return 0;
 28: }

 30: static PetscErrorCode DMForestPackageInitialize(void)
 31: {
 32:   if (DMForestPackageInitialized) return 0;
 33:   DMForestPackageInitialized = PETSC_TRUE;

 35:   DMForestRegisterType(DMFOREST);
 36:   PetscRegisterFinalize(DMForestPackageFinalize);
 37:   return 0;
 38: }

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

 43:   Not Collective

 45:   Input parameter:
 46: . name - the name of the type

 48:   Level: advanced

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

 56:   DMForestPackageInitialize();
 57:   PetscNew(&link);
 58:   PetscStrallocpy(name, &link->name);
 59:   link->next       = DMForestTypeList;
 60:   DMForestTypeList = link;
 61:   return 0;
 62: }

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

 67:   Not Collective

 69:   Input parameter:
 70: . dm - the DM object

 72:   Output parameter:
 73: . isForest - whether dm is a subtype of DMFOREST

 75:   Level: intermediate

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

 83:   while (link) {
 84:     PetscBool sameType;
 85:     PetscObjectTypeCompare((PetscObject)dm, link->name, &sameType);
 86:     if (sameType) {
 87:       *isForest = PETSC_TRUE;
 88:       return 0;
 89:     }
 90:     link = link->next;
 91:   }
 92:   *isForest = PETSC_FALSE;
 93:   return 0;
 94: }

 96: /*@
 97:   DMForestTemplate - Create a new DM that will be adapted from a source DM.  The new DM reproduces the configuration
 98:   of the source, but is not yet setup, so that the user can then define only the ways that the new DM should differ
 99:   (by, e.g., refinement or repartitioning).  The source DM is also set as the adaptivity source DM of the new DM (see
100:   DMForestSetAdaptivityForest()).

102:   Collective on dm

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

108:   Output Parameter:
109: . tdm - the new DM object

111:   Level: intermediate

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

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

158:     DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
159:     DMSetPeriodicity(*tdm, maxCell, Lstart, L);
160:   }
161:   DMGetMatType(dm, &mtype);
162:   DMSetMatType(*tdm, mtype);
163:   return 0;
164: }

166: static PetscErrorCode DMInitialize_Forest(DM dm);

168: PETSC_EXTERN PetscErrorCode DMClone_Forest(DM dm, DM *newdm)
169: {
170:   DM_Forest  *forest = (DM_Forest *)dm->data;
171:   const char *type;

173:   forest->refct++;
174:   (*newdm)->data = forest;
175:   PetscObjectGetType((PetscObject)dm, &type);
176:   PetscObjectChangeTypeName((PetscObject)*newdm, type);
177:   DMInitialize_Forest(*newdm);
178:   return 0;
179: }

181: static PetscErrorCode DMDestroy_Forest(DM dm)
182: {
183:   DM_Forest *forest = (DM_Forest *)dm->data;

185:   if (--forest->refct > 0) return 0;
186:   if (forest->destroy) (*forest->destroy)(dm);
187:   PetscSFDestroy(&forest->cellSF);
188:   PetscSFDestroy(&forest->preCoarseToFine);
189:   PetscSFDestroy(&forest->coarseToPreFine);
190:   DMLabelDestroy(&forest->adaptLabel);
191:   PetscFree(forest->adaptStrategy);
192:   DMDestroy(&forest->base);
193:   DMDestroy(&forest->adapt);
194:   PetscFree(forest->topology);
195:   PetscFree(forest);
196:   return 0;
197: }

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

204:   Logically collective on dm

206:   Input parameters:
207: + dm - the forest
208: - topology - the topology of the forest

210:   Level: intermediate

212: .seealso: `DMForestGetTopology()`, `DMForestSetBaseDM()`
213: @*/
214: PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology)
215: {
216:   DM_Forest *forest = (DM_Forest *)dm->data;

220:   PetscFree(forest->topology);
221:   PetscStrallocpy((const char *)topology, (char **)&forest->topology);
222:   return 0;
223: }

225: /*@C
226:   DMForestGetTopology - Get a string describing the topology of a DMForest.

228:   Not collective

230:   Input parameter:
231: . dm - the forest

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

236:   Level: intermediate

238: .seealso: `DMForestSetTopology()`
239: @*/
240: PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology)
241: {
242:   DM_Forest *forest = (DM_Forest *)dm->data;

246:   *topology = forest->topology;
247:   return 0;
248: }

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

255:   Logically collective on dm

257:   Input Parameters:
258: + dm - the forest
259: - base - the base DM of the forest

261:   Notes:
262:     Currently the base DM must be a DMPLEX

264:   Level: intermediate

266: .seealso: `DMForestGetBaseDM()`
267: @*/
268: PetscErrorCode DMForestSetBaseDM(DM dm, DM base)
269: {
270:   DM_Forest *forest = (DM_Forest *)dm->data;
271:   PetscInt   dim, dimEmbed;

275:   PetscObjectReference((PetscObject)base);
276:   DMDestroy(&forest->base);
277:   forest->base = base;
278:   if (base) {
279:     const PetscReal *maxCell, *Lstart, *L;

282:     DMGetDimension(base, &dim);
283:     DMSetDimension(dm, dim);
284:     DMGetCoordinateDim(base, &dimEmbed);
285:     DMSetCoordinateDim(dm, dimEmbed);
286:     DMGetPeriodicity(base, &maxCell, &Lstart, &L);
287:     DMSetPeriodicity(dm, maxCell, Lstart, L);
288:   } else DMSetPeriodicity(dm, NULL, NULL, NULL);
289:   return 0;
290: }

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

297:   Not collective

299:   Input Parameter:
300: . dm - the forest

302:   Output Parameter:
303: . base - the base DM of the forest

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

308:   Level: intermediate

310: .seealso: `DMForestSetBaseDM()`
311: @*/
312: PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
313: {
314:   DM_Forest *forest = (DM_Forest *)dm->data;

318:   *base = forest->base;
319:   return 0;
320: }

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

327:   forest->mapcoordinates    = func;
328:   forest->mapcoordinatesctx = ctx;
329:   return 0;
330: }

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

337:   if (func) *func = forest->mapcoordinates;
338:   if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
339:   return 0;
340: }

342: /*@
343:   DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the current forest will be
344:   adapted (e.g., the current forest will be refined/coarsened/repartitioned from it) im DMSetUp().  Usually not needed
345:   by users directly: DMForestTemplate() constructs a new forest to be adapted from an old forest and calls this
346:   routine.

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

351:   Logically collective on dm

353:   Input Parameters:
354: + dm - the new forest, which will be constructed from adapt
355: - adapt - the old forest

357:   Level: intermediate

359: .seealso: `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
360: @*/
361: PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
362: {
363:   DM_Forest *forest, *adaptForest, *oldAdaptForest;
364:   DM         oldAdapt;
365:   PetscBool  isForest;

369:   DMIsForest(dm, &isForest);
370:   if (!isForest) return 0;
372:   forest = (DM_Forest *)dm->data;
373:   DMForestGetAdaptivityForest(dm, &oldAdapt);
374:   adaptForest    = (DM_Forest *)(adapt ? adapt->data : NULL);
375:   oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
376:   if (adaptForest != oldAdaptForest) {
377:     PetscSFDestroy(&forest->preCoarseToFine);
378:     PetscSFDestroy(&forest->coarseToPreFine);
379:     if (forest->clearadaptivityforest) (*forest->clearadaptivityforest)(dm);
380:   }
381:   switch (forest->adaptPurpose) {
382:   case DM_ADAPT_DETERMINE:
383:     PetscObjectReference((PetscObject)adapt);
384:     DMDestroy(&(forest->adapt));
385:     forest->adapt = adapt;
386:     break;
387:   case DM_ADAPT_REFINE:
388:     DMSetCoarseDM(dm, adapt);
389:     break;
390:   case DM_ADAPT_COARSEN:
391:   case DM_ADAPT_COARSEN_LAST:
392:     DMSetFineDM(dm, adapt);
393:     break;
394:   default:
395:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
396:   }
397:   return 0;
398: }

400: /*@
401:   DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.

403:   Not collective

405:   Input Parameter:
406: . dm - the forest

408:   Output Parameter:
409: . adapt - the forest from which dm is/was adapted

411:   Level: intermediate

413: .seealso: `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
414: @*/
415: PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
416: {
417:   DM_Forest *forest;

420:   forest = (DM_Forest *)dm->data;
421:   switch (forest->adaptPurpose) {
422:   case DM_ADAPT_DETERMINE:
423:     *adapt = forest->adapt;
424:     break;
425:   case DM_ADAPT_REFINE:
426:     DMGetCoarseDM(dm, adapt);
427:     break;
428:   case DM_ADAPT_COARSEN:
429:   case DM_ADAPT_COARSEN_LAST:
430:     DMGetFineDM(dm, adapt);
431:     break;
432:   default:
433:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
434:   }
435:   return 0;
436: }

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

447:   Logically collective on dm

449:   Input Parameters:
450: + dm - the forest
451: - purpose - the adaptivity purpose

453:   Level: advanced

455: .seealso: `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
456: @*/
457: PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
458: {
459:   DM_Forest *forest;

461:   forest = (DM_Forest *)dm->data;
463:   if (purpose != forest->adaptPurpose) {
464:     DM adapt;

466:     DMForestGetAdaptivityForest(dm, &adapt);
467:     PetscObjectReference((PetscObject)adapt);
468:     DMForestSetAdaptivityForest(dm, NULL);

470:     forest->adaptPurpose = purpose;

472:     DMForestSetAdaptivityForest(dm, adapt);
473:     DMDestroy(&adapt);
474:   }
475:   return 0;
476: }

478: /*@
479:   DMForestGetAdaptivityPurpose - Get whether the current DM is being adapted from its source (set with
480:   DMForestSetAdaptivityForest()) for the purpose of refinement (DM_ADAPT_REFINE), coarsening (DM_ADAPT_COARSEN),
481:   coarsening only the last level (DM_ADAPT_COARSEN_LAST) or undefined (DM_ADAPT_DETERMINE).
482:   This only matters for the purposes of reference counting: during DMDestroy(), cyclic
483:   references can be found between DMs only if the cyclic reference is due to a fine/coarse relationship (see
484:   DMSetFineDM()/DMSetCoarseDM()).  If the purpose is not refinement or coarsening, and the user does not maintain a
485:   reference to the post-adaptation forest (i.e., the one created by DMForestTemplate()), then this can cause a memory
486:   leak.  This method is used by subtypes of DMForest when automatically constructing mesh hierarchies.

488:   Not collective

490:   Input Parameter:
491: . dm - the forest

493:   Output Parameter:
494: . purpose - the adaptivity purpose

496:   Level: advanced

498: .seealso: `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
499: @*/
500: PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
501: {
502:   DM_Forest *forest;

504:   forest   = (DM_Forest *)dm->data;
505:   *purpose = forest->adaptPurpose;
506:   return 0;
507: }

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

513:   Logically collective on dm

515:   Input Parameters:
516: + dm - the forest
517: - adjDim - default 0 (i.e., vertices determine adjacency)

519:   Level: intermediate

521: .seealso: `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
522: @*/
523: PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
524: {
525:   PetscInt   dim;
526:   DM_Forest *forest = (DM_Forest *)dm->data;

531:   DMGetDimension(dm, &dim);
533:   forest->adjDim = adjDim;
534:   return 0;
535: }

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

541:   Logically collective on dm

543:   Input Parameters:
544: + dm - the forest
545: - adjCodim - default isthe dimension of the forest (see DMGetDimension()), since this is the codimension of vertices

547:   Level: intermediate

549: .seealso: `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
550: @*/
551: PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
552: {
553:   PetscInt dim;

556:   DMGetDimension(dm, &dim);
557:   DMForestSetAdjacencyDimension(dm, dim - adjCodim);
558:   return 0;
559: }

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

565:   Not collective

567:   Input Parameter:
568: . dm - the forest

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

573:   Level: intermediate

575: .seealso: `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
576: @*/
577: PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim)
578: {
579:   DM_Forest *forest = (DM_Forest *)dm->data;

583:   *adjDim = forest->adjDim;
584:   return 0;
585: }

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

591:   Not collective

593:   Input Parameter:
594: . dm - the forest

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

599:   Level: intermediate

601: .seealso: `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
602: @*/
603: PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
604: {
605:   DM_Forest *forest = (DM_Forest *)dm->data;
606:   PetscInt   dim;

610:   DMGetDimension(dm, &dim);
611:   *adjCodim = dim - forest->adjDim;
612:   return 0;
613: }

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

620:   Logically collective on dm

622:   Input Parameters:
623: + dm - the forest
624: - overlap - default 0

626:   Level: intermediate

628: .seealso: `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
629: @*/
630: PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
631: {
632:   DM_Forest *forest = (DM_Forest *)dm->data;

637:   forest->overlap = overlap;
638:   return 0;
639: }

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

645:   Not collective

647:   Input Parameter:
648: . dm - the forest

650:   Output Parameter:
651: . overlap - default 0

653:   Level: intermediate

655: .seealso: `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
656: @*/
657: PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
658: {
659:   DM_Forest *forest = (DM_Forest *)dm->data;

663:   *overlap = forest->overlap;
664:   return 0;
665: }

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

672:   Logically collective on dm

674:   Input Parameters:
675: + dm - the forest
676: - minRefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

678:   Level: intermediate

680: .seealso: `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
681: @*/
682: PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
683: {
684:   DM_Forest *forest = (DM_Forest *)dm->data;

688:   forest->minRefinement = minRefinement;
689:   return 0;
690: }

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

697:   Not collective

699:   Input Parameter:
700: . dm - the forest

702:   Output Parameter:
703: . minRefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

705:   Level: intermediate

707: .seealso: `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
708: @*/
709: PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
710: {
711:   DM_Forest *forest = (DM_Forest *)dm->data;

715:   *minRefinement = forest->minRefinement;
716:   return 0;
717: }

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

723:   Logically collective on dm

725:   Input Parameters:
726: + dm - the forest
727: - initefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

729:   Level: intermediate

731: .seealso: `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
732: @*/
733: PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement)
734: {
735:   DM_Forest *forest = (DM_Forest *)dm->data;

739:   forest->initRefinement = initRefinement;
740:   return 0;
741: }

743: /*@
744:   DMForestGetInitialRefinement - Get the initial level of refinement (relative to the base DM, see
745:   DMForestGetBaseDM()) allowed in the forest.

747:   Not collective

749:   Input Parameter:
750: . dm - the forest

752:   Output Parameter:
753: . initRefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

755:   Level: intermediate

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

765:   *initRefinement = forest->initRefinement;
766:   return 0;
767: }

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

774:   Logically collective on dm

776:   Input Parameters:
777: + dm - the forest
778: - maxRefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

780:   Level: intermediate

782: .seealso: `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()`
783: @*/
784: PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement)
785: {
786:   DM_Forest *forest = (DM_Forest *)dm->data;

790:   forest->maxRefinement = maxRefinement;
791:   return 0;
792: }

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

799:   Not collective

801:   Input Parameter:
802: . dm - the forest

804:   Output Parameter:
805: . maxRefinement - default PETSC_DEFAULT (interpreted by the subtype of DMForest)

807:   Level: intermediate

809: .seealso: `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
810: @*/
811: PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement)
812: {
813:   DM_Forest *forest = (DM_Forest *)dm->data;

817:   *maxRefinement = forest->maxRefinement;
818:   return 0;
819: }

821: /*@C
822:   DMForestSetAdaptivityStrategy - During the pre-setup phase, set the strategy for combining adaptivity labels from multiple processes.
823:   Subtypes of DMForest may define their own strategies.  Two default strategies are DMFORESTADAPTALL, which indicates that all processes must agree
824:   for a refinement/coarsening flag to be valid, and DMFORESTADAPTANY, which indicates that only one process needs to
825:   specify refinement/coarsening.

827:   Logically collective on dm

829:   Input Parameters:
830: + dm - the forest
831: - adaptStrategy - default DMFORESTADAPTALL

833:   Level: advanced

835: .seealso: `DMForestGetAdaptivityStrategy()`
836: @*/
837: PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
838: {
839:   DM_Forest *forest = (DM_Forest *)dm->data;

842:   PetscFree(forest->adaptStrategy);
843:   PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy);
844:   return 0;
845: }

847: /*@C
848:   DMForestSetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.  Subtypes
849:   of DMForest may define their own strategies.  Two default strategies are DMFORESTADAPTALL, which indicates that all
850:   processes must agree for a refinement/coarsening flag to be valid, and DMFORESTADAPTANY, which indicates that only
851:   one process needs to specify refinement/coarsening.

853:   Not collective

855:   Input Parameter:
856: . dm - the forest

858:   Output Parameter:
859: . adaptStrategy - the adaptivity strategy (default DMFORESTADAPTALL)

861:   Level: advanced

863: .seealso: `DMForestSetAdaptivityStrategy()`
864: @*/
865: PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
866: {
867:   DM_Forest *forest = (DM_Forest *)dm->data;

871:   *adaptStrategy = forest->adaptStrategy;
872:   return 0;
873: }

875: /*@
876:   DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
877:   etc.) was successful.  PETSC_FALSE indicates that the post-adaptation forest is the same as the pre-adpatation
878:   forest.  A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
879:   exceeded the maximum refinement level.

881:   Collective on dm

883:   Input Parameter:

885: . dm - the post-adaptation forest

887:   Output Parameter:

889: . success - PETSC_TRUE if the post-adaptation forest is different from the pre-adaptation forest.

891:   Level: intermediate

893: .see
894: @*/
895: PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
896: {
897:   DM_Forest *forest;

901:   forest = (DM_Forest *)dm->data;
902:   (forest->getadaptivitysuccess)(dm, success);
903:   return 0;
904: }

906: /*@
907:   DMForestSetComputeAdaptivitySF - During the pre-setup phase, set whether transfer PetscSFs should be computed
908:   relating the cells of the pre-adaptation forest to the post-adaptiation forest.  After DMSetUp() is called, these transfer PetscSFs can be accessed with DMForestGetAdaptivitySF().

910:   Logically collective on dm

912:   Input Parameters:
913: + dm - the post-adaptation forest
914: - computeSF - default PETSC_TRUE

916:   Level: advanced

918: .seealso: `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
919: @*/
920: PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
921: {
922:   DM_Forest *forest;

926:   forest                 = (DM_Forest *)dm->data;
927:   forest->computeAdaptSF = computeSF;
928:   return 0;
929: }

931: PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
932: {
933:   DM_Forest *forest;

939:   forest = (DM_Forest *)dmIn->data;
941:   (forest->transfervec)(dmIn, vecIn, dmOut, vecOut, useBCs, time);
942:   return 0;
943: }

945: PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
946: {
947:   DM_Forest *forest;

952:   forest = (DM_Forest *)dm->data;
954:   (forest->transfervecfrombase)(dm, vecIn, vecOut);
955:   return 0;
956: }

958: /*@
959:   DMForestGetComputeAdaptivitySF - Get whether transfer PetscSFs should be computed relating the cells of the
960:   pre-adaptation forest to the post-adaptiation forest.  After DMSetUp() is called, these transfer PetscSFs can be
961:   accessed with DMForestGetAdaptivitySF().

963:   Not collective

965:   Input Parameter:
966: . dm - the post-adaptation forest

968:   Output Parameter:
969: . computeSF - default PETSC_TRUE

971:   Level: advanced

973: .seealso: `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
974: @*/
975: PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
976: {
977:   DM_Forest *forest;

980:   forest     = (DM_Forest *)dm->data;
981:   *computeSF = forest->computeAdaptSF;
982:   return 0;
983: }

985: /*@
986:   DMForestGetAdaptivitySF - Get PetscSFs that relate the pre-adaptation forest to the post-adaptation forest.
987:   Adaptation can be any combination of refinement, coarsening, repartition, and change of overlap, so there may be
988:   some cells of the pre-adaptation that are parents of post-adaptation cells, and vice versa.  Therefore there are two
989:   PetscSFs: one that relates pre-adaptation coarse cells to post-adaptation fine cells, and one that relates
990:   pre-adaptation fine cells to post-adaptation coarse cells.

992:   Not collective

994:   Input Parameter:
995:   dm - the post-adaptation forest

997:   Output Parameter:
998:   preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
999:   coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-

1001:   Level: advanced

1003: .seealso: `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
1004: @*/
1005: PetscErrorCode DMForestGetAdaptivitySF(DM dm, PetscSF *preCoarseToFine, PetscSF *coarseToPreFine)
1006: {
1007:   DM_Forest *forest;

1010:   DMSetUp(dm);
1011:   forest = (DM_Forest *)dm->data;
1012:   if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
1013:   if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
1014:   return 0;
1015: }

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

1022:   Logically collective on dm

1024:   Input Parameters:
1025: + dm - the forest
1026: - grade - the grading factor

1028:   Level: advanced

1030: .seealso: `DMForestGetGradeFactor()`
1031: @*/
1032: PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade)
1033: {
1034:   DM_Forest *forest = (DM_Forest *)dm->data;

1038:   forest->gradeFactor = grade;
1039:   return 0;
1040: }

1042: /*@
1043:   DMForestGetGradeFactor - Get the desired amount of grading in the mesh, e.g. give 2 to indicate that the diameter of
1044:   neighboring cells should differ by at most a factor of 2.  Subtypes of DMForest may only support one particular
1045:   choice of grading factor.

1047:   Not collective

1049:   Input Parameter:
1050: . dm - the forest

1052:   Output Parameter:
1053: . grade - the grading factor

1055:   Level: advanced

1057: .seealso: `DMForestSetGradeFactor()`
1058: @*/
1059: PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
1060: {
1061:   DM_Forest *forest = (DM_Forest *)dm->data;

1065:   *grade = forest->gradeFactor;
1066:   return 0;
1067: }

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

1076:   Logically collective on dm

1078:   Input Parameters:
1079: + dm - the forest
1080: - weightsFactors - default 1.

1082:   Level: advanced

1084: .seealso: `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()`
1085: @*/
1086: PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor)
1087: {
1088:   DM_Forest *forest = (DM_Forest *)dm->data;

1092:   forest->weightsFactor = weightsFactor;
1093:   return 0;
1094: }

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

1103:   Not collective

1105:   Input Parameter:
1106: . dm - the forest

1108:   Output Parameter:
1109: . weightsFactors - default 1.

1111:   Level: advanced

1113: .seealso: `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
1114: @*/
1115: PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
1116: {
1117:   DM_Forest *forest = (DM_Forest *)dm->data;

1121:   *weightsFactor = forest->weightsFactor;
1122:   return 0;
1123: }

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

1128:   Not collective

1130:   Input Parameter:
1131: . dm - the forest

1133:   Output Parameters:
1134: + cStart - the first cell on this process
1135: - cEnd - one after the final cell on this process

1137:   Level: intermediate

1139: .seealso: `DMForestGetCellSF()`
1140: @*/
1141: PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
1142: {
1143:   DM_Forest *forest = (DM_Forest *)dm->data;

1148:   if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) forest->createcellchart(dm, &forest->cStart, &forest->cEnd);
1149:   *cStart = forest->cStart;
1150:   *cEnd   = forest->cEnd;
1151:   return 0;
1152: }

1154: /*@
1155:   DMForestGetCellSF - After the setup phase, get the PetscSF for overlapping cells between processes

1157:   Not collective

1159:   Input Parameter:
1160: . dm - the forest

1162:   Output Parameter:
1163: . cellSF - the PetscSF

1165:   Level: intermediate

1167: .seealso: `DMForestGetCellChart()`
1168: @*/
1169: PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
1170: {
1171:   DM_Forest *forest = (DM_Forest *)dm->data;

1175:   if ((!forest->cellSF) && forest->createcellsf) forest->createcellsf(dm, &forest->cellSF);
1176:   *cellSF = forest->cellSF;
1177:   return 0;
1178: }

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

1186:   Logically collective on dm

1188:   Input Parameters:
1189: - dm - the forest
1190: + adaptLabel - the label in the pre-adaptation forest

1192:   Level: intermediate

1194: .seealso `DMForestGetAdaptivityLabel()`
1195: @*/
1196: PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
1197: {
1198:   DM_Forest *forest = (DM_Forest *)dm->data;

1202:   PetscObjectReference((PetscObject)adaptLabel);
1203:   DMLabelDestroy(&forest->adaptLabel);
1204:   forest->adaptLabel = adaptLabel;
1205:   return 0;
1206: }

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

1214:   Not collective

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

1219:   Output Parameter:
1220: . adaptLabel - the name of the label in the pre-adaptation forest

1222:   Level: intermediate

1224: .seealso `DMForestSetAdaptivityLabel()`
1225: @*/
1226: PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
1227: {
1228:   DM_Forest *forest = (DM_Forest *)dm->data;

1231:   *adaptLabel = forest->adaptLabel;
1232:   return 0;
1233: }

1235: /*@
1236:   DMForestSetCellWeights - Set the weights assigned to each of the cells (see DMForestGetCellChart()) of the current
1237:   process: weights are used to determine parallel partitioning.  Partitions will be created so that each process's
1238:   ratio of weight to capacity (see DMForestSetWeightCapacity()) is roughly equal. If NULL, each cell receives a weight
1239:   of 1.

1241:   Logically collective on dm

1243:   Input Parameters:
1244: + dm - the forest
1245: . weights - the array of weights for all cells, or NULL to indicate each cell has weight 1.
1246: - copyMode - how weights should reference weights

1248:   Level: advanced

1250: .seealso: `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
1251: @*/
1252: PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
1253: {
1254:   DM_Forest *forest = (DM_Forest *)dm->data;
1255:   PetscInt   cStart, cEnd;

1258:   DMForestGetCellChart(dm, &cStart, &cEnd);
1260:   if (copyMode == PETSC_COPY_VALUES) {
1261:     if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscMalloc1(cEnd - cStart, &forest->cellWeights);
1262:     PetscArraycpy(forest->cellWeights, weights, cEnd - cStart);
1263:     forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
1264:     return 0;
1265:   }
1266:   if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscFree(forest->cellWeights);
1267:   forest->cellWeights         = weights;
1268:   forest->cellWeightsCopyMode = copyMode;
1269:   return 0;
1270: }

1272: /*@
1273:   DMForestGetCellWeights - Get the weights assigned to each of the cells (see DMForestGetCellChart()) of the current
1274:   process: weights are used to determine parallel partitioning.  Partitions will be created so that each process's
1275:   ratio of weight to capacity (see DMForestSetWeightCapacity()) is roughly equal. If NULL, each cell receives a weight
1276:   of 1.

1278:   Not collective

1280:   Input Parameter:
1281: . dm - the forest

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

1286:   Level: advanced

1288: .seealso: `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
1289: @*/
1290: PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
1291: {
1292:   DM_Forest *forest = (DM_Forest *)dm->data;

1296:   *weights = forest->cellWeights;
1297:   return 0;
1298: }

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

1306:   Logically Collective on dm

1308:   Input parameters:
1309: + dm - the forest
1310: - capacity - this process's capacity

1312:   Level: advanced

1314: .seealso `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1315: @*/
1316: PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
1317: {
1318:   DM_Forest *forest = (DM_Forest *)dm->data;

1323:   forest->weightCapacity = capacity;
1324:   return 0;
1325: }

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

1333:   Not collective

1335:   Input parameter:
1336: . dm - the forest

1338:   Output parameter:
1339: . capacity - this process's capacity

1341:   Level: advanced

1343: .seealso `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1344: @*/
1345: PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
1346: {
1347:   DM_Forest *forest = (DM_Forest *)dm->data;

1351:   *capacity = forest->weightCapacity;
1352:   return 0;
1353: }

1355: PETSC_EXTERN PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems *PetscOptionsObject)
1356: {
1357:   PetscBool                  flg, flg1, flg2, flg3, flg4;
1358:   DMForestTopology           oldTopo;
1359:   char                       stringBuffer[256];
1360:   PetscViewer                viewer;
1361:   PetscViewerFormat          format;
1362:   PetscInt                   adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
1363:   PetscReal                  weightsFactor;
1364:   DMForestAdaptivityStrategy adaptStrategy;

1366:   DMForestGetTopology(dm, &oldTopo);
1367:   PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
1368:   PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1);
1369:   PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2);
1370:   PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3);
1371:   PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4);
1373:   if (flg1) {
1374:     DMForestSetTopology(dm, (DMForestTopology)stringBuffer);
1375:     DMForestSetBaseDM(dm, NULL);
1376:     DMForestSetAdaptivityForest(dm, NULL);
1377:   }
1378:   if (flg2) {
1379:     DM base;

1381:     DMCreate(PetscObjectComm((PetscObject)dm), &base);
1382:     PetscViewerPushFormat(viewer, format);
1383:     DMLoad(base, viewer);
1384:     PetscViewerDestroy(&viewer);
1385:     DMForestSetBaseDM(dm, base);
1386:     DMDestroy(&base);
1387:     DMForestSetTopology(dm, NULL);
1388:     DMForestSetAdaptivityForest(dm, NULL);
1389:   }
1390:   if (flg3) {
1391:     DM coarse;

1393:     DMCreate(PetscObjectComm((PetscObject)dm), &coarse);
1394:     PetscViewerPushFormat(viewer, format);
1395:     DMLoad(coarse, viewer);
1396:     PetscViewerDestroy(&viewer);
1397:     DMForestSetAdaptivityForest(dm, coarse);
1398:     DMDestroy(&coarse);
1399:     DMForestSetTopology(dm, NULL);
1400:     DMForestSetBaseDM(dm, NULL);
1401:   }
1402:   if (flg4) {
1403:     DM fine;

1405:     DMCreate(PetscObjectComm((PetscObject)dm), &fine);
1406:     PetscViewerPushFormat(viewer, format);
1407:     DMLoad(fine, viewer);
1408:     PetscViewerDestroy(&viewer);
1409:     DMForestSetAdaptivityForest(dm, fine);
1410:     DMDestroy(&fine);
1411:     DMForestSetTopology(dm, NULL);
1412:     DMForestSetBaseDM(dm, NULL);
1413:   }
1414:   DMForestGetAdjacencyDimension(dm, &adjDim);
1415:   PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0);
1416:   if (flg) {
1417:     DMForestSetAdjacencyDimension(dm, adjDim);
1418:   } else {
1419:     DMForestGetAdjacencyCodimension(dm, &adjCodim);
1420:     PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1);
1421:     if (flg) DMForestSetAdjacencyCodimension(dm, adjCodim);
1422:   }
1423:   DMForestGetPartitionOverlap(dm, &overlap);
1424:   PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0);
1425:   if (flg) DMForestSetPartitionOverlap(dm, overlap);
1426: #if 0
1427:   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);
1428:   if (flg) {
1429:     DMForestSetMinimumRefinement(dm,minRefinement);
1430:     DMForestSetInitialRefinement(dm,minRefinement);
1431:   }
1432:   PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0);
1433:   if (flg) {
1434:     DMForestSetMinimumRefinement(dm,0);
1435:     DMForestSetInitialRefinement(dm,initRefinement);
1436:   }
1437: #endif
1438:   DMForestGetMinimumRefinement(dm, &minRefinement);
1439:   PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0);
1440:   if (flg) DMForestSetMinimumRefinement(dm, minRefinement);
1441:   DMForestGetInitialRefinement(dm, &initRefinement);
1442:   PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0);
1443:   if (flg) DMForestSetInitialRefinement(dm, initRefinement);
1444:   DMForestGetMaximumRefinement(dm, &maxRefinement);
1445:   PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0);
1446:   if (flg) DMForestSetMaximumRefinement(dm, maxRefinement);
1447:   DMForestGetAdaptivityStrategy(dm, &adaptStrategy);
1448:   PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg);
1449:   if (flg) DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer);
1450:   DMForestGetGradeFactor(dm, &grade);
1451:   PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0);
1452:   if (flg) DMForestSetGradeFactor(dm, grade);
1453:   DMForestGetCellWeightFactor(dm, &weightsFactor);
1454:   PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg);
1455:   if (flg) DMForestSetCellWeightFactor(dm, weightsFactor);
1456:   PetscOptionsHeadEnd();
1457:   return 0;
1458: }

1460: PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1461: {
1462:   if (subdm) DMClone(dm, subdm);
1463:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
1464:   return 0;
1465: }

1467: PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
1468: {
1469:   DMLabel refine;
1470:   DM      fineDM;

1472:   DMGetFineDM(dm, &fineDM);
1473:   if (fineDM) {
1474:     PetscObjectReference((PetscObject)fineDM);
1475:     *dmRefined = fineDM;
1476:     return 0;
1477:   }
1478:   DMForestTemplate(dm, comm, dmRefined);
1479:   DMGetLabel(dm, "refine", &refine);
1480:   if (!refine) {
1481:     DMLabelCreate(PETSC_COMM_SELF, "refine", &refine);
1482:     DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE);
1483:   } else PetscObjectReference((PetscObject)refine);
1484:   DMForestSetAdaptivityLabel(*dmRefined, refine);
1485:   DMLabelDestroy(&refine);
1486:   return 0;
1487: }

1489: PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
1490: {
1491:   DMLabel coarsen;
1492:   DM      coarseDM;

1494:   {
1495:     PetscMPIInt mpiComparison;
1496:     MPI_Comm    dmcomm = PetscObjectComm((PetscObject)dm);

1498:     MPI_Comm_compare(comm, dmcomm, &mpiComparison);
1500:   }
1501:   DMGetCoarseDM(dm, &coarseDM);
1502:   if (coarseDM) {
1503:     PetscObjectReference((PetscObject)coarseDM);
1504:     *dmCoarsened = coarseDM;
1505:     return 0;
1506:   }
1507:   DMForestTemplate(dm, comm, dmCoarsened);
1508:   DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN);
1509:   DMGetLabel(dm, "coarsen", &coarsen);
1510:   if (!coarsen) {
1511:     DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen);
1512:     DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN);
1513:   } else PetscObjectReference((PetscObject)coarsen);
1514:   DMForestSetAdaptivityLabel(*dmCoarsened, coarsen);
1515:   DMLabelDestroy(&coarsen);
1516:   return 0;
1517: }

1519: PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
1520: {
1521:   PetscBool success;

1523:   DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM);
1524:   DMForestSetAdaptivityLabel(*adaptedDM, label);
1525:   DMSetUp(*adaptedDM);
1526:   DMForestGetAdaptivitySuccess(*adaptedDM, &success);
1527:   if (!success) {
1528:     DMDestroy(adaptedDM);
1529:     *adaptedDM = NULL;
1530:   }
1531:   return 0;
1532: }

1534: static PetscErrorCode DMInitialize_Forest(DM dm)
1535: {
1536:   PetscMemzero(dm->ops, sizeof(*(dm->ops)));

1538:   dm->ops->clone          = DMClone_Forest;
1539:   dm->ops->setfromoptions = DMSetFromOptions_Forest;
1540:   dm->ops->destroy        = DMDestroy_Forest;
1541:   dm->ops->createsubdm    = DMCreateSubDM_Forest;
1542:   dm->ops->refine         = DMRefine_Forest;
1543:   dm->ops->coarsen        = DMCoarsen_Forest;
1544:   return 0;
1545: }

1547: /*MC

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

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

1560:   Level: advanced

1562: .seealso: `DMType`, `DMCreate()`, `DMSetType()`, `DMForestGetBaseDM()`, `DMForestSetBaseDM()`, `DMForestTemplate()`, `DMForestSetAdaptivityLabel()`
1563: M*/

1565: PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
1566: {
1567:   DM_Forest *forest;

1570:   PetscNew(&forest);
1571:   dm->dim                     = 0;
1572:   dm->data                    = forest;
1573:   forest->refct               = 1;
1574:   forest->data                = NULL;
1575:   forest->topology            = NULL;
1576:   forest->adapt               = NULL;
1577:   forest->base                = NULL;
1578:   forest->adaptPurpose        = DM_ADAPT_DETERMINE;
1579:   forest->adjDim              = PETSC_DEFAULT;
1580:   forest->overlap             = PETSC_DEFAULT;
1581:   forest->minRefinement       = PETSC_DEFAULT;
1582:   forest->maxRefinement       = PETSC_DEFAULT;
1583:   forest->initRefinement      = PETSC_DEFAULT;
1584:   forest->cStart              = PETSC_DETERMINE;
1585:   forest->cEnd                = PETSC_DETERMINE;
1586:   forest->cellSF              = NULL;
1587:   forest->adaptLabel          = NULL;
1588:   forest->gradeFactor         = 2;
1589:   forest->cellWeights         = NULL;
1590:   forest->cellWeightsCopyMode = PETSC_USE_POINTER;
1591:   forest->weightsFactor       = 1.;
1592:   forest->weightCapacity      = 1.;
1593:   DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL);
1594:   DMInitialize_Forest(dm);
1595:   return 0;
1596: }