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