Actual source code: forest.c
1: #include <petsc/private/dmforestimpl.h>
2: #include <petsc/private/dmimpl.h>
3: #include <petsc/private/dmlabelimpl.h>
4: #include <petscsf.h>
6: PetscBool DMForestPackageInitialized = PETSC_FALSE;
8: typedef struct _DMForestTypeLink *DMForestTypeLink;
10: struct _DMForestTypeLink {
11: char *name;
12: DMForestTypeLink next;
13: };
15: DMForestTypeLink DMForestTypeList;
17: static PetscErrorCode DMForestPackageFinalize(void)
18: {
19: DMForestTypeLink oldLink, link = DMForestTypeList;
21: PetscFunctionBegin;
22: while (link) {
23: oldLink = link;
24: PetscCall(PetscFree(oldLink->name));
25: link = oldLink->next;
26: PetscCall(PetscFree(oldLink));
27: }
28: PetscFunctionReturn(PETSC_SUCCESS);
29: }
31: static PetscErrorCode DMForestPackageInitialize(void)
32: {
33: PetscFunctionBegin;
34: if (DMForestPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
35: DMForestPackageInitialized = PETSC_TRUE;
37: PetscCall(DMForestRegisterType(DMFOREST));
38: PetscCall(PetscRegisterFinalize(DMForestPackageFinalize));
39: PetscFunctionReturn(PETSC_SUCCESS);
40: }
42: /*@C
43: DMForestRegisterType - Registers a `DMType` as a subtype of `DMFOREST` (so that `DMIsForest()` will be correct)
45: Not Collective
47: Input Parameter:
48: . name - the name of the type
50: Level: advanced
52: .seealso: `DMFOREST`, `DMIsForest()`
53: @*/
54: PetscErrorCode DMForestRegisterType(DMType name)
55: {
56: DMForestTypeLink link;
58: PetscFunctionBegin;
59: PetscCall(DMForestPackageInitialize());
60: PetscCall(PetscNew(&link));
61: PetscCall(PetscStrallocpy(name, &link->name));
62: link->next = DMForestTypeList;
63: DMForestTypeList = link;
64: PetscFunctionReturn(PETSC_SUCCESS);
65: }
67: /*@
68: DMIsForest - Check whether a DM uses the DMFOREST interface for hierarchically-refined meshes
70: Not Collective
72: Input Parameter:
73: . dm - the DM object
75: Output Parameter:
76: . isForest - whether dm is a subtype of DMFOREST
78: Level: intermediate
80: .seealso: `DMFOREST`, `DMForestRegisterType()`
81: @*/
82: PetscErrorCode DMIsForest(DM dm, PetscBool *isForest)
83: {
84: DMForestTypeLink link = DMForestTypeList;
86: PetscFunctionBegin;
87: while (link) {
88: PetscBool sameType;
89: PetscCall(PetscObjectTypeCompare((PetscObject)dm, link->name, &sameType));
90: if (sameType) {
91: *isForest = PETSC_TRUE;
92: PetscFunctionReturn(PETSC_SUCCESS);
93: }
94: link = link->next;
95: }
96: *isForest = PETSC_FALSE;
97: PetscFunctionReturn(PETSC_SUCCESS);
98: }
100: /*@
101: DMForestTemplate - Create a new `DM` that will be adapted from a source `DM`.
103: Collective
105: Input Parameters:
106: + dm - the source `DM` object
107: - comm - the communicator for the new `DM` (this communicator is currently ignored, but is present so that `DMForestTemplate()` can be used within `DMCoarsen()`)
109: Output Parameter:
110: . tedm - the new `DM` object
112: Level: intermediate
114: Notes:
115: The new `DM` reproduces the configuration of the source, but is not yet setup, so that the
116: user can then define only the ways that the new `DM` should differ (by, e.g., refinement or
117: repartitioning). The source `DM` is also set as the adaptivity source `DM` of the new `DM`
118: (see `DMForestSetAdaptivityForest()`).
120: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`
121: @*/
122: PetscErrorCode DMForestTemplate(DM dm, MPI_Comm comm, DM *tedm)
123: {
124: DM_Forest *forest = (DM_Forest *)dm->data;
125: DMType type;
126: DM base;
127: DMForestTopology topology;
128: MatType mtype;
129: PetscInt dim, overlap, ref, factor;
130: DMForestAdaptivityStrategy strat;
131: void *ctx;
132: PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
133: void *mapCtx;
135: PetscFunctionBegin;
137: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), tedm));
138: PetscCall(DMGetType(dm, &type));
139: PetscCall(DMSetType(*tedm, type));
140: PetscCall(DMForestGetBaseDM(dm, &base));
141: PetscCall(DMForestSetBaseDM(*tedm, base));
142: PetscCall(DMForestGetTopology(dm, &topology));
143: PetscCall(DMForestSetTopology(*tedm, topology));
144: PetscCall(DMForestGetAdjacencyDimension(dm, &dim));
145: PetscCall(DMForestSetAdjacencyDimension(*tedm, dim));
146: PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
147: PetscCall(DMForestSetPartitionOverlap(*tedm, overlap));
148: PetscCall(DMForestGetMinimumRefinement(dm, &ref));
149: PetscCall(DMForestSetMinimumRefinement(*tedm, ref));
150: PetscCall(DMForestGetMaximumRefinement(dm, &ref));
151: PetscCall(DMForestSetMaximumRefinement(*tedm, ref));
152: PetscCall(DMForestGetAdaptivityStrategy(dm, &strat));
153: PetscCall(DMForestSetAdaptivityStrategy(*tedm, strat));
154: PetscCall(DMForestGetGradeFactor(dm, &factor));
155: PetscCall(DMForestSetGradeFactor(*tedm, factor));
156: PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
157: PetscCall(DMForestSetBaseCoordinateMapping(*tedm, map, mapCtx));
158: if (forest->ftemplate) PetscCall((*forest->ftemplate)(dm, *tedm));
159: PetscCall(DMForestSetAdaptivityForest(*tedm, dm));
160: PetscCall(DMCopyDisc(dm, *tedm));
161: PetscCall(DMGetApplicationContext(dm, &ctx));
162: PetscCall(DMSetApplicationContext(*tedm, &ctx));
163: {
164: const PetscReal *maxCell, *L, *Lstart;
166: PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
167: PetscCall(DMSetPeriodicity(*tedm, maxCell, Lstart, L));
168: }
169: PetscCall(DMGetMatType(dm, &mtype));
170: PetscCall(DMSetMatType(*tedm, mtype));
171: PetscFunctionReturn(PETSC_SUCCESS);
172: }
174: static PetscErrorCode DMInitialize_Forest(DM dm);
176: PetscErrorCode DMClone_Forest(DM dm, DM *newdm)
177: {
178: DM_Forest *forest = (DM_Forest *)dm->data;
179: const char *type;
181: PetscFunctionBegin;
182: forest->refct++;
183: (*newdm)->data = forest;
184: PetscCall(PetscObjectGetType((PetscObject)dm, &type));
185: PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, type));
186: PetscCall(DMInitialize_Forest(*newdm));
187: PetscFunctionReturn(PETSC_SUCCESS);
188: }
190: static PetscErrorCode DMDestroy_Forest(DM dm)
191: {
192: DM_Forest *forest = (DM_Forest *)dm->data;
194: PetscFunctionBegin;
195: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_plex_p4est_C", NULL));
196: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_p4est_plex_C", NULL));
197: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_plex_p8est_C", NULL));
198: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMConvert_p8est_plex_C", NULL));
199: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
200: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
201: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
202: PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
203: if (--forest->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
204: if (forest->destroy) PetscCall((*forest->destroy)(dm));
205: PetscCall(PetscSFDestroy(&forest->cellSF));
206: PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
207: PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
208: PetscCall(DMLabelDestroy(&forest->adaptLabel));
209: PetscCall(PetscFree(forest->adaptStrategy));
210: PetscCall(DMDestroy(&forest->base));
211: PetscCall(DMDestroy(&forest->adapt));
212: PetscCall(PetscFree(forest->topology));
213: PetscCall(PetscFree(forest));
214: PetscFunctionReturn(PETSC_SUCCESS);
215: }
217: /*@
218: DMForestSetTopology - Set the topology of a `DMFOREST` during the pre-setup phase. The topology is a string (e.g.
219: "cube", "shell") and can be interpreted by subtypes of `DMFOREST`) to construct the base DM of a forest during
220: `DMSetUp()`.
222: Logically collectiv
224: Input Parameters:
225: + dm - the forest
226: - topology - the topology of the forest
228: Level: intermediate
230: .seealso: `DM`, `DMFOREST`, `DMForestGetTopology()`, `DMForestSetBaseDM()`
231: @*/
232: PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology)
233: {
234: DM_Forest *forest = (DM_Forest *)dm->data;
236: PetscFunctionBegin;
238: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the topology after setup");
239: PetscCall(PetscFree(forest->topology));
240: PetscCall(PetscStrallocpy((const char *)topology, (char **)&forest->topology));
241: PetscFunctionReturn(PETSC_SUCCESS);
242: }
244: /*@
245: DMForestGetTopology - Get a string describing the topology of a `DMFOREST`.
247: Not Collective
249: Input Parameter:
250: . dm - the forest
252: Output Parameter:
253: . topology - the topology of the forest (e.g., `cube`, `shell`)
255: Level: intermediate
257: .seealso: `DM`, `DMFOREST`, `DMForestSetTopology()`
258: @*/
259: PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology)
260: {
261: DM_Forest *forest = (DM_Forest *)dm->data;
263: PetscFunctionBegin;
265: PetscAssertPointer(topology, 2);
266: *topology = forest->topology;
267: PetscFunctionReturn(PETSC_SUCCESS);
268: }
270: /*@
271: DMForestSetBaseDM - During the pre-setup phase, set the `DM` that defines the base mesh of a
272: `DMFOREST` forest.
274: Logically Collective
276: Input Parameters:
277: + dm - the forest
278: - base - the base `DM` of the forest
280: Level: intermediate
282: Notes:
283: The forest will be hierarchically refined from the base, and all refinements/coarsenings of
284: the forest will share its base. In general, two forest must share a base to be comparable,
285: to do things like construct interpolators.
287: Currently the base `DM` must be a `DMPLEX`
289: .seealso: `DM`, `DMFOREST`, `DMForestGetBaseDM()`
290: @*/
291: PetscErrorCode DMForestSetBaseDM(DM dm, DM base)
292: {
293: DM_Forest *forest = (DM_Forest *)dm->data;
294: PetscInt dim, dimEmbed;
296: PetscFunctionBegin;
298: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the base after setup");
299: PetscCall(PetscObjectReference((PetscObject)base));
300: PetscCall(DMDestroy(&forest->base));
301: forest->base = base;
302: if (base) {
303: const PetscReal *maxCell, *Lstart, *L;
306: PetscCall(DMGetDimension(base, &dim));
307: PetscCall(DMSetDimension(dm, dim));
308: PetscCall(DMGetCoordinateDim(base, &dimEmbed));
309: PetscCall(DMSetCoordinateDim(dm, dimEmbed));
310: PetscCall(DMGetPeriodicity(base, &maxCell, &Lstart, &L));
311: PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
312: } else PetscCall(DMSetPeriodicity(dm, NULL, NULL, NULL));
313: PetscFunctionReturn(PETSC_SUCCESS);
314: }
316: /*@
317: DMForestGetBaseDM - Get the base `DM` of a `DMFOREST`
319: Not Collective
321: Input Parameter:
322: . dm - the forest
324: Output Parameter:
325: . base - the base `DM` of the forest
327: Level: intermediate
329: Notes:
330: After DMSetUp(), the base DM will be redundantly distributed across MPI processes
332: The forest will be hierarchically refined from the base, and all refinements/coarsenings of
333: the forest will share its base. In general, two forest must share a base to be comparable,
334: to do things like construct interpolators.
336: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()`
337: @*/
338: PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
339: {
340: DM_Forest *forest = (DM_Forest *)dm->data;
342: PetscFunctionBegin;
344: PetscAssertPointer(base, 2);
345: *base = forest->base;
346: PetscFunctionReturn(PETSC_SUCCESS);
347: }
349: /*@C
350: DMForestSetBaseCoordinateMapping - Set a user-supplied mapping that is applied to the base `DM`'s coordinates when the forest computes coordinates for refined cells.
352: Logically Collective
354: Input Parameters:
355: + dm - the `DMFOREST`
356: . func - callback that maps reference coordinates to physical coordinates
357: - ctx - optional application context passed through to `func`
359: Calling sequence of `func`:
360: + base - the base `DM` of the forest
361: . coarsePoint - the base-`DM` cell that owns the coordinate being mapped
362: . dim - the coordinate dimension (at most 3)
363: . coordIn - the input coordinate on the base `DM`
364: . coordOut - the mapped coordinate to be written
365: - ctx - optional application context
367: Level: intermediate
369: .seealso: `DM`, `DMFOREST`, `DMForestGetBaseCoordinateMapping()`, `DMForestSetBaseDM()`
370: @*/
371: PetscErrorCode DMForestSetBaseCoordinateMapping(DM dm, PetscErrorCode (*func)(DM base, PetscInt coarsePoint, PetscInt dim, const PetscReal coordIn[], PetscReal coordOut[], PetscCtx ctx), PetscCtx ctx)
372: {
373: DM_Forest *forest = (DM_Forest *)dm->data;
375: PetscFunctionBegin;
377: forest->mapcoordinates = func;
378: forest->mapcoordinatesctx = ctx;
379: PetscFunctionReturn(PETSC_SUCCESS);
380: }
382: /*@C
383: DMForestGetBaseCoordinateMapping - Get the user-supplied coordinate mapping previously set with `DMForestSetBaseCoordinateMapping()`.
385: Not Collective
387: Input Parameter:
388: . dm - the `DMFOREST`
390: Output Parameters:
391: + func - the callback, or `NULL`
392: - ctx - the application context that was registered with the callback, or `NULL`
394: Calling sequence of `func`:
395: + base - the base `DM` of the forest
396: . coarsePoint - the base-`DM` cell that owns the coordinate being mapped
397: . dim - the coordinate dimension (at most 3)
398: . coordIn - the input coordinate on the base `DM`
399: . coordOut - the mapped coordinate to be written
400: - ctx - optional application context
402: Level: intermediate
404: .seealso: `DM`, `DMFOREST`, `DMForestSetBaseCoordinateMapping()`
405: @*/
406: PetscErrorCode DMForestGetBaseCoordinateMapping(DM dm, PetscErrorCode (**func)(DM base, PetscInt coarsePoint, PetscInt dim, const PetscReal coordIn[], PetscReal coordOut[], PetscCtx ctx), PetscCtxRt ctx)
407: {
408: DM_Forest *forest = (DM_Forest *)dm->data;
410: PetscFunctionBegin;
412: if (func) *func = forest->mapcoordinates;
413: if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
414: PetscFunctionReturn(PETSC_SUCCESS);
415: }
417: /*@
418: DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the
419: current forest will be adapted (e.g., the current forest will be
420: refined/coarsened/repartitioned from it) in `DMSetUp()`.
422: Logically Collective
424: Input Parameters:
425: + dm - the new forest, which will be constructed from adapt
426: - adapt - the old forest
428: Level: intermediate
430: Note:
431: Usually not needed by users directly, `DMForestTemplate()` constructs a new forest to be
432: adapted from an old forest and calls this routine.
434: This can be called after setup with `adapt` = `NULL`, which will clear all internal data
435: related to the adaptivity forest from `dm`. This way, repeatedly adapting does not leave
436: stale `DM` objects in memory.
438: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
439: @*/
440: PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
441: {
442: DM_Forest *forest, *adaptForest, *oldAdaptForest;
443: DM oldAdapt;
444: PetscBool isForest;
446: PetscFunctionBegin;
449: PetscCall(DMIsForest(dm, &isForest));
450: if (!isForest) PetscFunctionReturn(PETSC_SUCCESS);
451: PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
452: forest = (DM_Forest *)dm->data;
453: PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt));
454: adaptForest = (DM_Forest *)(adapt ? adapt->data : NULL);
455: oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
456: if (adaptForest != oldAdaptForest) {
457: PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
458: PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
459: if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm));
460: }
461: switch (forest->adaptPurpose) {
462: case DM_ADAPT_DETERMINE:
463: PetscCall(PetscObjectReference((PetscObject)adapt));
464: PetscCall(DMDestroy(&forest->adapt));
465: forest->adapt = adapt;
466: break;
467: case DM_ADAPT_REFINE:
468: PetscCall(DMSetCoarseDM(dm, adapt));
469: break;
470: case DM_ADAPT_COARSEN:
471: case DM_ADAPT_COARSEN_LAST:
472: PetscCall(DMSetFineDM(dm, adapt));
473: break;
474: default:
475: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
476: }
477: PetscFunctionReturn(PETSC_SUCCESS);
478: }
480: /*@
481: DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.
483: Not Collective
485: Input Parameter:
486: . dm - the forest
488: Output Parameter:
489: . adapt - the forest from which `dm` is/was adapted
491: Level: intermediate
493: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
494: @*/
495: PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
496: {
497: DM_Forest *forest;
499: PetscFunctionBegin;
501: forest = (DM_Forest *)dm->data;
502: switch (forest->adaptPurpose) {
503: case DM_ADAPT_DETERMINE:
504: *adapt = forest->adapt;
505: break;
506: case DM_ADAPT_REFINE:
507: PetscCall(DMGetCoarseDM(dm, adapt));
508: break;
509: case DM_ADAPT_COARSEN:
510: case DM_ADAPT_COARSEN_LAST:
511: PetscCall(DMGetFineDM(dm, adapt));
512: break;
513: default:
514: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
515: }
516: PetscFunctionReturn(PETSC_SUCCESS);
517: }
519: /*@
520: DMForestSetAdaptivityPurpose - During the pre-setup phase, set whether the current `DM` is being adapted from its
521: source (set with `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening
522: (`DM_ADAPT_COARSEN`), or undefined (`DM_ADAPT_DETERMINE`).
524: Logically Collective
526: Input Parameters:
527: + dm - the forest
528: - purpose - the adaptivity purpose
530: Level: advanced
532: Notes:
533: This only matters for reference counting during `DMDestroy()`. Cyclic references
534: can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
535: (see `DMSetFineDM()`/`DMSetCoarseDM()`). If the purpose is not refinement or coarsening, and
536: the user does not maintain a reference to the post-adaptation forest (i.e., the one created
537: by `DMForestTemplate()`), this can cause a memory leak. This method is used by subtypes
538: of `DMFOREST` when automatically constructing mesh hierarchies.
540: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
541: @*/
542: PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
543: {
544: DM_Forest *forest;
546: PetscFunctionBegin;
547: forest = (DM_Forest *)dm->data;
548: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
549: if (purpose != forest->adaptPurpose) {
550: DM adapt;
552: PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
553: PetscCall(PetscObjectReference((PetscObject)adapt));
554: PetscCall(DMForestSetAdaptivityForest(dm, NULL));
556: forest->adaptPurpose = purpose;
558: PetscCall(DMForestSetAdaptivityForest(dm, adapt));
559: PetscCall(DMDestroy(&adapt));
560: }
561: PetscFunctionReturn(PETSC_SUCCESS);
562: }
564: /*@
565: DMForestGetAdaptivityPurpose - Get whether the current `DM` is being adapted from its source (set with
566: `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening (`DM_ADAPT_COARSEN`),
567: coarsening only the last level (`DM_ADAPT_COARSEN_LAST`) or undefined (`DM_ADAPT_DETERMINE`).
569: Not Collective
571: Input Parameter:
572: . dm - the forest
574: Output Parameter:
575: . purpose - the adaptivity purpose
577: Level: advanced
579: Notes:
580: This only matters for reference counting: during `DMDestroy()`. Cyclic references
581: can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
582: (See `DMSetFineDM()`/`DMSetCoarseDM()`). If the purpose is not refinement or coarsening, and
583: the user does not maintain a reference to the post-adaptation forest (i.e., the one created
584: by `DMForestTemplate()`), this can cause a memory leak. This method is used by subtypes
585: of `DMFOREST` when automatically constructing mesh hierarchies.
587: .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
588: @*/
589: PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
590: {
591: DM_Forest *forest;
593: PetscFunctionBegin;
594: forest = (DM_Forest *)dm->data;
595: *purpose = forest->adaptPurpose;
596: PetscFunctionReturn(PETSC_SUCCESS);
597: }
599: /*@
600: DMForestSetAdjacencyDimension - During the pre-setup phase, set the dimension of interface points that determine
601: cell adjacency (for the purposes of partitioning and overlap).
603: Logically Collective
605: Input Parameters:
606: + dm - the forest
607: - adjDim - default 0 (i.e., vertices determine adjacency)
609: Level: intermediate
611: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
612: @*/
613: PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
614: {
615: PetscInt dim;
616: DM_Forest *forest = (DM_Forest *)dm->data;
618: PetscFunctionBegin;
620: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup");
621: PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim);
622: PetscCall(DMGetDimension(dm, &dim));
623: PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim);
624: forest->adjDim = adjDim;
625: PetscFunctionReturn(PETSC_SUCCESS);
626: }
628: /*@
629: DMForestSetAdjacencyCodimension - Like `DMForestSetAdjacencyDimension()`, but specified as a co-dimension (so that,
630: e.g., adjacency based on facets can be specified by codimension 1 in all cases)
632: Logically Collective
634: Input Parameters:
635: + dm - the forest
636: - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices
638: Level: intermediate
640: .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
641: @*/
642: PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
643: {
644: PetscInt dim;
646: PetscFunctionBegin;
648: PetscCall(DMGetDimension(dm, &dim));
649: PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim));
650: PetscFunctionReturn(PETSC_SUCCESS);
651: }
653: /*@
654: DMForestGetAdjacencyDimension - Get the dimension of interface points that determine cell adjacency (for the
655: purposes of partitioning and overlap).
657: Not Collective
659: Input Parameter:
660: . dm - the forest
662: Output Parameter:
663: . adjDim - default 0 (i.e., vertices determine adjacency)
665: Level: intermediate
667: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
668: @*/
669: PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim)
670: {
671: DM_Forest *forest = (DM_Forest *)dm->data;
673: PetscFunctionBegin;
675: PetscAssertPointer(adjDim, 2);
676: *adjDim = forest->adjDim;
677: PetscFunctionReturn(PETSC_SUCCESS);
678: }
680: /*@
681: DMForestGetAdjacencyCodimension - Like `DMForestGetAdjacencyDimension()`, but specified as a co-dimension (so that,
682: e.g., adjacency based on facets can be specified by codimension 1 in all cases)
684: Not Collective
686: Input Parameter:
687: . dm - the forest
689: Output Parameter:
690: . adjCodim - default isthe dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices
692: Level: intermediate
694: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
695: @*/
696: PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
697: {
698: DM_Forest *forest = (DM_Forest *)dm->data;
699: PetscInt dim;
701: PetscFunctionBegin;
703: PetscAssertPointer(adjCodim, 2);
704: PetscCall(DMGetDimension(dm, &dim));
705: *adjCodim = dim - forest->adjDim;
706: PetscFunctionReturn(PETSC_SUCCESS);
707: }
709: /*@
710: DMForestSetPartitionOverlap - During the pre-setup phase, set the amount of cell-overlap present in parallel
711: partitions of a forest, with values > 0 indicating subdomains that are expanded by that many iterations of adding
712: adjacent cells
714: Logically Collective
716: Input Parameters:
717: + dm - the forest
718: - overlap - default 0
720: Level: intermediate
722: .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
723: @*/
724: PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
725: {
726: DM_Forest *forest = (DM_Forest *)dm->data;
728: PetscFunctionBegin;
730: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup");
731: PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap);
732: forest->overlap = overlap;
733: PetscFunctionReturn(PETSC_SUCCESS);
734: }
736: /*@
737: DMForestGetPartitionOverlap - Get the amount of cell-overlap present in parallel partitions of a forest, with values
738: > 0 indicating subdomains that are expanded by that many iterations of adding adjacent cells
740: Not Collective
742: Input Parameter:
743: . dm - the forest
745: Output Parameter:
746: . overlap - default 0
748: Level: intermediate
750: .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
751: @*/
752: PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
753: {
754: DM_Forest *forest = (DM_Forest *)dm->data;
756: PetscFunctionBegin;
758: PetscAssertPointer(overlap, 2);
759: *overlap = forest->overlap;
760: PetscFunctionReturn(PETSC_SUCCESS);
761: }
763: /*@
764: DMForestSetMinimumRefinement - During the pre-setup phase, set the minimum level of refinement (relative to the base
765: `DM`, see `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by coarsening a previous forest
766: (see `DMForestGetAdaptivityForest()`) this limits the amount of coarsening.
768: Logically Collective
770: Input Parameters:
771: + dm - the forest
772: - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
774: Level: intermediate
776: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
777: @*/
778: PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
779: {
780: DM_Forest *forest = (DM_Forest *)dm->data;
782: PetscFunctionBegin;
784: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the minimum refinement after setup");
785: forest->minRefinement = minRefinement;
786: PetscFunctionReturn(PETSC_SUCCESS);
787: }
789: /*@
790: DMForestGetMinimumRefinement - Get the minimum level of refinement (relative to the base `DM`, see
791: `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by coarsening a previous forest (see
792: `DMForestGetAdaptivityForest()`), this limits the amount of coarsening.
794: Not Collective
796: Input Parameter:
797: . dm - the forest
799: Output Parameter:
800: . minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
802: Level: intermediate
804: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
805: @*/
806: PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
807: {
808: DM_Forest *forest = (DM_Forest *)dm->data;
810: PetscFunctionBegin;
812: PetscAssertPointer(minRefinement, 2);
813: *minRefinement = forest->minRefinement;
814: PetscFunctionReturn(PETSC_SUCCESS);
815: }
817: /*@
818: DMForestSetInitialRefinement - During the pre-setup phase, set the initial level of refinement (relative to the base
819: `DM`, see `DMForestGetBaseDM()`) allowed in the forest.
821: Logically Collective
823: Input Parameters:
824: + dm - the forest
825: - initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
827: Level: intermediate
829: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
830: @*/
831: PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement)
832: {
833: DM_Forest *forest = (DM_Forest *)dm->data;
835: PetscFunctionBegin;
837: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup");
838: forest->initRefinement = initRefinement;
839: PetscFunctionReturn(PETSC_SUCCESS);
840: }
842: /*@
843: DMForestGetInitialRefinement - Get the initial level of refinement (relative to the base `DM`, see
844: `DMForestGetBaseDM()`) allowed in the forest.
846: Not Collective
848: Input Parameter:
849: . dm - the forest
851: Output Parameter:
852: . initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
854: Level: intermediate
856: .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
857: @*/
858: PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement)
859: {
860: DM_Forest *forest = (DM_Forest *)dm->data;
862: PetscFunctionBegin;
864: PetscAssertPointer(initRefinement, 2);
865: *initRefinement = forest->initRefinement;
866: PetscFunctionReturn(PETSC_SUCCESS);
867: }
869: /*@
870: DMForestSetMaximumRefinement - During the pre-setup phase, set the maximum level of refinement (relative to the base
871: `DM`, see `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by refining a previous forest
872: (see `DMForestGetAdaptivityForest()`), this limits the amount of refinement.
874: Logically Collective
876: Input Parameters:
877: + dm - the forest
878: - maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
880: Level: intermediate
882: .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()`
883: @*/
884: PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement)
885: {
886: DM_Forest *forest = (DM_Forest *)dm->data;
888: PetscFunctionBegin;
890: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup");
891: forest->maxRefinement = maxRefinement;
892: PetscFunctionReturn(PETSC_SUCCESS);
893: }
895: /*@
896: DMForestGetMaximumRefinement - Get the maximum level of refinement (relative to the base `DM`, see
897: `DMForestGetBaseDM()`) allowed in the forest. If the forest is being created by refining a previous forest (see
898: `DMForestGetAdaptivityForest()`), this limits the amount of refinement.
900: Not Collective
902: Input Parameter:
903: . dm - the forest
905: Output Parameter:
906: . maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
908: Level: intermediate
910: .seealso: `DM`, `DMFOREST`, `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
911: @*/
912: PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement)
913: {
914: DM_Forest *forest = (DM_Forest *)dm->data;
916: PetscFunctionBegin;
918: PetscAssertPointer(maxRefinement, 2);
919: *maxRefinement = forest->maxRefinement;
920: PetscFunctionReturn(PETSC_SUCCESS);
921: }
923: /*@
924: DMForestSetAdaptivityStrategy - During the pre-setup phase, set the strategy for combining adaptivity labels from multiple processes.
926: Logically Collective
928: Input Parameters:
929: + dm - the forest
930: - adaptStrategy - default `DMFORESTADAPTALL`
932: Level: advanced
934: Notes:
935: Subtypes of `DMFOREST` may define their own strategies. Two default strategies are `DMFORESTADAPTALL`, which indicates that all processes must agree
936: for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only one process needs to
937: specify refinement/coarsening.
939: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`
940: @*/
941: PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
942: {
943: DM_Forest *forest = (DM_Forest *)dm->data;
945: PetscFunctionBegin;
947: PetscCall(PetscFree(forest->adaptStrategy));
948: PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy));
949: PetscFunctionReturn(PETSC_SUCCESS);
950: }
952: /*@
953: DMForestGetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.
955: Not Collective
957: Input Parameter:
958: . dm - the forest
960: Output Parameter:
961: . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`)
963: Level: advanced
965: Note:
966: Subtypes
967: of `DMFOREST` may define their own strategies. Two default strategies are `DMFORESTADAPTALL`, which indicates that all
968: processes must agree for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only
969: one process needs to specify refinement/coarsening.
971: .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()`
972: @*/
973: PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
974: {
975: DM_Forest *forest = (DM_Forest *)dm->data;
977: PetscFunctionBegin;
979: PetscAssertPointer(adaptStrategy, 2);
980: *adaptStrategy = forest->adaptStrategy;
981: PetscFunctionReturn(PETSC_SUCCESS);
982: }
984: /*@
985: DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
986: etc.) was successful.
988: Collective
990: Input Parameter:
991: . dm - the post-adaptation forest
993: Output Parameter:
994: . success - `PETSC_TRUE` if the post-adaptation forest is different from the pre-adaptation forest.
996: Level: intermediate
998: Notes:
999: `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adaptation
1000: forest. A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
1001: exceeded the maximum refinement level.
1003: .seealso: `DM`, `DMFOREST`
1004: @*/
1005: PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
1006: {
1007: DM_Forest *forest;
1009: PetscFunctionBegin;
1011: PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet.");
1012: forest = (DM_Forest *)dm->data;
1013: PetscCall(forest->getadaptivitysuccess(dm, success));
1014: PetscFunctionReturn(PETSC_SUCCESS);
1015: }
1017: /*@
1018: DMForestSetComputeAdaptivitySF - During the pre-setup phase, set whether transfer `PetscSF`s should be computed
1019: relating the cells of the pre-adaptation forest to the post-adaptiation forest.
1021: Logically Collective
1023: Input Parameters:
1024: + dm - the post-adaptation forest
1025: - computeSF - default `PETSC_TRUE`
1027: Level: advanced
1029: Note:
1030: After `DMSetUp()` is called, the transfer `PetscSF`s can be accessed with `DMForestGetAdaptivitySF()`.
1032: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
1033: @*/
1034: PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
1035: {
1036: DM_Forest *forest;
1038: PetscFunctionBegin;
1040: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called");
1041: forest = (DM_Forest *)dm->data;
1042: forest->computeAdaptSF = computeSF;
1043: PetscFunctionReturn(PETSC_SUCCESS);
1044: }
1046: /*@
1047: DMForestTransferVec - Transfer a `Vec` between two related `DMFOREST` grids, e.g. before and after adaptation.
1049: Collective
1051: Input Parameters:
1052: + dmIn - source `DMFOREST`
1053: . vecIn - vector on `dmIn`
1054: . dmOut - destination `DMFOREST`
1055: . useBCs - if `PETSC_TRUE`, apply boundary conditions during transfer
1056: - time - simulation time supplied to any time-dependent boundary conditions
1058: Output Parameter:
1059: . vecOut - vector on `dmOut` that receives the transferred values
1061: Level: intermediate
1063: Note:
1064: Requires the forest implementation to provide a transfer routine; otherwise raises `PETSC_ERR_SUP`.
1066: .seealso: `DM`, `DMFOREST`, `DMForestTransferVecFromBase()`, `DMForestSetAdaptivityForest()`
1067: @*/
1068: PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
1069: {
1070: DM_Forest *forest;
1072: PetscFunctionBegin;
1077: forest = (DM_Forest *)dmIn->data;
1078: PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented");
1079: PetscCall(forest->transfervec(dmIn, vecIn, dmOut, vecOut, useBCs, time));
1080: PetscFunctionReturn(PETSC_SUCCESS);
1081: }
1083: /*@
1084: DMForestTransferVecFromBase - Transfer a `Vec` defined on the base `DM` of a `DMFOREST` onto the refined forest.
1086: Collective
1088: Input Parameters:
1089: + dm - the `DMFOREST`
1090: - vecIn - vector defined on the base `DM` returned by `DMForestGetBaseDM()`
1092: Output Parameter:
1093: . vecOut - vector on `dm` that receives the transferred values
1095: Level: intermediate
1097: Note:
1098: Requires the forest implementation to provide a base-to-forest transfer routine; otherwise raises `PETSC_ERR_SUP`.
1100: .seealso: `DM`, `DMFOREST`, `DMForestTransferVec()`, `DMForestGetBaseDM()`
1101: @*/
1102: PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
1103: {
1104: DM_Forest *forest;
1106: PetscFunctionBegin;
1110: forest = (DM_Forest *)dm->data;
1111: PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented");
1112: PetscCall(forest->transfervecfrombase(dm, vecIn, vecOut));
1113: PetscFunctionReturn(PETSC_SUCCESS);
1114: }
1116: /*@
1117: DMForestGetComputeAdaptivitySF - Get whether transfer `PetscSF`s should be computed relating the cells of the
1118: pre-adaptation forest to the post-adaptiation forest. After `DMSetUp()` is called, these transfer PetscSFs can be
1119: accessed with `DMForestGetAdaptivitySF()`.
1121: Not Collective
1123: Input Parameter:
1124: . dm - the post-adaptation forest
1126: Output Parameter:
1127: . computeSF - default `PETSC_TRUE`
1129: Level: advanced
1131: .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
1132: @*/
1133: PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
1134: {
1135: DM_Forest *forest;
1137: PetscFunctionBegin;
1139: forest = (DM_Forest *)dm->data;
1140: *computeSF = forest->computeAdaptSF;
1141: PetscFunctionReturn(PETSC_SUCCESS);
1142: }
1144: /*@
1145: DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the
1146: post-adaptation forest.
1148: Not Collective
1150: Input Parameter:
1151: . dm - the post-adaptation forest
1153: Output Parameters:
1154: + preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
1155: - coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-
1157: Level: advanced
1159: Notes:
1160: Adaptation can be any combination of refinement, coarsening, repartition, and change of
1161: overlap, so there may be some cells of the pre-adaptation that are parents of post-adaptation
1162: cells, and vice versa. Therefore there are two `PetscSF`s: one that relates pre-adaptation
1163: coarse cells to post-adaptation fine cells, and one that relates pre-adaptation fine cells to
1164: post-adaptation coarse cells.
1166: .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
1167: @*/
1168: PetscErrorCode DMForestGetAdaptivitySF(DM dm, PeOp PetscSF *preCoarseToFine, PeOp PetscSF *coarseToPreFine)
1169: {
1170: DM_Forest *forest;
1172: PetscFunctionBegin;
1174: PetscCall(DMSetUp(dm));
1175: forest = (DM_Forest *)dm->data;
1176: if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
1177: if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
1178: PetscFunctionReturn(PETSC_SUCCESS);
1179: }
1181: /*@
1182: DMForestSetGradeFactor - During the pre-setup phase, set the desired amount of grading in the
1183: mesh, e.g. give 2 to indicate that the diameter of neighboring cells should differ by at most
1184: a factor of 2.
1186: Logically Collective
1188: Input Parameters:
1189: + dm - the forest
1190: - grade - the grading factor
1192: Level: advanced
1194: Note:
1195: Subtypes of `DMFOREST` may only support one particular choice of grading factor.
1197: .seealso: `DM`, `DMFOREST`, `DMForestGetGradeFactor()`
1198: @*/
1199: PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade)
1200: {
1201: DM_Forest *forest = (DM_Forest *)dm->data;
1203: PetscFunctionBegin;
1205: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup");
1206: forest->gradeFactor = grade;
1207: PetscFunctionReturn(PETSC_SUCCESS);
1208: }
1210: /*@
1211: DMForestGetGradeFactor - Get the desired amount of grading in the mesh, e.g. give 2 to indicate that the diameter of
1212: neighboring cells should differ by at most a factor of 2. Subtypes of `DMFOREST` may only support one particular
1213: choice of grading factor.
1215: Not Collective
1217: Input Parameter:
1218: . dm - the forest
1220: Output Parameter:
1221: . grade - the grading factor
1223: Level: advanced
1225: .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()`
1226: @*/
1227: PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
1228: {
1229: DM_Forest *forest = (DM_Forest *)dm->data;
1231: PetscFunctionBegin;
1233: PetscAssertPointer(grade, 2);
1234: *grade = forest->gradeFactor;
1235: PetscFunctionReturn(PETSC_SUCCESS);
1236: }
1238: /*@
1239: DMForestSetCellWeightFactor - During the pre-setup phase, set the factor by which the level of refinement changes
1240: the cell weight (see `DMForestSetCellWeights()`) when calculating partitions.
1242: Logically Collective
1244: Input Parameters:
1245: + dm - the forest
1246: - weightsFactor - default 1.
1248: Level: advanced
1250: Note:
1251: The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel). A factor
1252: of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
1253: example, might be appropriate for sub-cycling time-stepping methods, when the computation
1254: associated with a cell is multiplied by a factor of 2 for each additional level of
1255: refinement.
1257: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()`
1258: @*/
1259: PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor)
1260: {
1261: DM_Forest *forest = (DM_Forest *)dm->data;
1263: PetscFunctionBegin;
1265: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup");
1266: forest->weightsFactor = weightsFactor;
1267: PetscFunctionReturn(PETSC_SUCCESS);
1268: }
1270: /*@
1271: DMForestGetCellWeightFactor - Get the factor by which the level of refinement changes the cell weight (see
1272: `DMForestSetCellWeights()`) when calculating partitions.
1274: Not Collective
1276: Input Parameter:
1277: . dm - the forest
1279: Output Parameter:
1280: . weightsFactor - default 1.
1282: Level: advanced
1284: Note:
1285: The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel). A factor
1286: of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
1287: example, might be appropriate for sub-cycling time-stepping methods, when the computation
1288: associated with a cell is multiplied by a factor of 2 for each additional level of
1289: refinement.
1291: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
1292: @*/
1293: PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
1294: {
1295: DM_Forest *forest = (DM_Forest *)dm->data;
1297: PetscFunctionBegin;
1299: PetscAssertPointer(weightsFactor, 2);
1300: *weightsFactor = forest->weightsFactor;
1301: PetscFunctionReturn(PETSC_SUCCESS);
1302: }
1304: /*@
1305: DMForestGetCellChart - After the setup phase, get the local half-open interval of the chart of cells on this process
1307: Not Collective
1309: Input Parameter:
1310: . dm - the forest
1312: Output Parameters:
1313: + cStart - the first cell on this process
1314: - cEnd - one after the final cell on this process
1316: Level: intermediate
1318: .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()`
1319: @*/
1320: PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
1321: {
1322: DM_Forest *forest = (DM_Forest *)dm->data;
1324: PetscFunctionBegin;
1326: PetscAssertPointer(cStart, 2);
1327: PetscAssertPointer(cEnd, 3);
1328: if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd));
1329: *cStart = forest->cStart;
1330: *cEnd = forest->cEnd;
1331: PetscFunctionReturn(PETSC_SUCCESS);
1332: }
1334: /*@
1335: DMForestGetCellSF - After the setup phase, get the `PetscSF` for overlapping cells between processes
1337: Not Collective
1339: Input Parameter:
1340: . dm - the forest
1342: Output Parameter:
1343: . cellSF - the `PetscSF`
1345: Level: intermediate
1347: .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()`
1348: @*/
1349: PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
1350: {
1351: DM_Forest *forest = (DM_Forest *)dm->data;
1353: PetscFunctionBegin;
1355: PetscAssertPointer(cellSF, 2);
1356: if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF));
1357: *cellSF = forest->cellSF;
1358: PetscFunctionReturn(PETSC_SUCCESS);
1359: }
1361: /*@
1362: DMForestSetAdaptivityLabel - During the pre-setup phase, set the label of the pre-adaptation forest (see
1363: `DMForestGetAdaptivityForest()`) that holds the adaptation flags (refinement, coarsening, or some combination).
1365: Logically Collective
1367: Input Parameters:
1368: + dm - the forest
1369: - adaptLabel - the label in the pre-adaptation forest
1371: Level: intermediate
1373: Note:
1374: The interpretation of the label values is up to the subtype of `DMFOREST`, but
1375: `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
1376: reserved as choices that should be accepted by all subtypes.
1378: .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()`
1379: @*/
1380: PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
1381: {
1382: DM_Forest *forest = (DM_Forest *)dm->data;
1384: PetscFunctionBegin;
1387: PetscCall(PetscObjectReference((PetscObject)adaptLabel));
1388: PetscCall(DMLabelDestroy(&forest->adaptLabel));
1389: forest->adaptLabel = adaptLabel;
1390: PetscFunctionReturn(PETSC_SUCCESS);
1391: }
1393: /*@
1394: DMForestGetAdaptivityLabel - Get the label of the pre-adaptation forest (see `DMForestGetAdaptivityForest()`) that
1395: holds the adaptation flags (refinement, coarsening, or some combination).
1397: Not Collective
1399: Input Parameter:
1400: . dm - the forest
1402: Output Parameter:
1403: . adaptLabel - the name of the label in the pre-adaptation forest
1405: Level: intermediate
1407: Note:
1408: The interpretation of the label values is up to the subtype of `DMFOREST`, but
1409: `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
1410: reserved as choices that should be accepted by all subtypes.
1412: .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()`
1413: @*/
1414: PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
1415: {
1416: DM_Forest *forest = (DM_Forest *)dm->data;
1418: PetscFunctionBegin;
1420: *adaptLabel = forest->adaptLabel;
1421: PetscFunctionReturn(PETSC_SUCCESS);
1422: }
1424: /*@
1425: DMForestSetCellWeights - Set the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
1426: process: weights are used to determine parallel partitioning.
1428: Logically Collective
1430: Input Parameters:
1431: + dm - the forest
1432: . weights - the array of weights (see `DMForestSetWeightCapacity()`) for all cells, or `NULL` to indicate each cell has weight 1.
1433: - copyMode - how weights should reference weights
1435: Level: advanced
1437: .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
1438: @*/
1439: PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
1440: {
1441: DM_Forest *forest = (DM_Forest *)dm->data;
1442: PetscInt cStart, cEnd;
1444: PetscFunctionBegin;
1446: PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
1447: PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd);
1448: if (copyMode == PETSC_COPY_VALUES) {
1449: if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights));
1450: PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart));
1451: forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
1452: PetscFunctionReturn(PETSC_SUCCESS);
1453: }
1454: if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights));
1455: forest->cellWeights = weights;
1456: forest->cellWeightsCopyMode = copyMode;
1457: PetscFunctionReturn(PETSC_SUCCESS);
1458: }
1460: /*@
1461: DMForestGetCellWeights - Get the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
1462: process: weights are used to determine parallel partitioning.
1464: Not Collective
1466: Input Parameter:
1467: . dm - the forest
1469: Output Parameter:
1470: . weights - the array of weights for all cells, or `NULL` to indicate each cell has weight 1.
1472: Level: advanced
1474: .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
1475: @*/
1476: PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
1477: {
1478: DM_Forest *forest = (DM_Forest *)dm->data;
1480: PetscFunctionBegin;
1482: PetscAssertPointer(weights, 2);
1483: *weights = forest->cellWeights;
1484: PetscFunctionReturn(PETSC_SUCCESS);
1485: }
1487: /*@
1488: DMForestSetWeightCapacity - During the pre-setup phase, set the capacity of the current process when repartitioning
1489: a pre-adaptation forest (see `DMForestGetAdaptivityForest()`).
1491: Logically Collective
1493: Input Parameters:
1494: + dm - the forest
1495: - capacity - this process's capacity
1497: Level: advanced
1499: Note:
1500: After partitioning, the ratio of the weight of each process's cells to the process's capacity
1501: will be roughly equal for all processes. A capacity of 0 indicates that the current process
1502: should not have any cells after repartitioning.
1504: .seealso: `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1505: @*/
1506: PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
1507: {
1508: DM_Forest *forest = (DM_Forest *)dm->data;
1510: PetscFunctionBegin;
1512: PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup");
1513: PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity);
1514: forest->weightCapacity = capacity;
1515: PetscFunctionReturn(PETSC_SUCCESS);
1516: }
1518: /*@
1519: DMForestGetWeightCapacity - Set the capacity of the current process when repartitioning a pre-adaptation forest (see
1520: `DMForestGetAdaptivityForest()`).
1522: Not Collective
1524: Input Parameter:
1525: . dm - the forest
1527: Output Parameter:
1528: . capacity - this process's capacity
1530: Level: advanced
1532: Note:
1533: After partitioning, the ratio of the weight of each process's cells to the process's capacity
1534: will be roughly equal for all processes. A capacity of 0 indicates that the current process
1535: should not have any cells after repartitioning.
1537: .seealso: `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1538: @*/
1539: PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
1540: {
1541: DM_Forest *forest = (DM_Forest *)dm->data;
1543: PetscFunctionBegin;
1545: PetscAssertPointer(capacity, 2);
1546: *capacity = forest->weightCapacity;
1547: PetscFunctionReturn(PETSC_SUCCESS);
1548: }
1550: PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems PetscOptionsObject)
1551: {
1552: PetscBool flg, flg1, flg2, flg3, flg4;
1553: DMForestTopology oldTopo;
1554: char stringBuffer[256];
1555: PetscViewer viewer;
1556: PetscViewerFormat format;
1557: PetscInt adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
1558: PetscReal weightsFactor;
1559: DMForestAdaptivityStrategy adaptStrategy;
1561: PetscFunctionBegin;
1562: PetscCall(DMForestGetTopology(dm, &oldTopo));
1563: PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
1564: PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1));
1565: PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2));
1566: PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3));
1567: PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4));
1568: PetscCheck((PetscInt)flg1 + (PetscInt)flg2 + (PetscInt)flg3 + (PetscInt)flg4 <= 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_INCOMP, "Specify only one of -dm_forest_{topology,base_dm,coarse_forest,fine_forest}");
1569: if (flg1) {
1570: PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer));
1571: PetscCall(DMForestSetBaseDM(dm, NULL));
1572: PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1573: }
1574: if (flg2) {
1575: DM base;
1577: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base));
1578: PetscCall(PetscViewerPushFormat(viewer, format));
1579: PetscCall(DMLoad(base, viewer));
1580: PetscCall(PetscViewerDestroy(&viewer));
1581: PetscCall(DMForestSetBaseDM(dm, base));
1582: PetscCall(DMDestroy(&base));
1583: PetscCall(DMForestSetTopology(dm, NULL));
1584: PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1585: }
1586: if (flg3) {
1587: DM coarse;
1589: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse));
1590: PetscCall(PetscViewerPushFormat(viewer, format));
1591: PetscCall(DMLoad(coarse, viewer));
1592: PetscCall(PetscViewerDestroy(&viewer));
1593: PetscCall(DMForestSetAdaptivityForest(dm, coarse));
1594: PetscCall(DMDestroy(&coarse));
1595: PetscCall(DMForestSetTopology(dm, NULL));
1596: PetscCall(DMForestSetBaseDM(dm, NULL));
1597: }
1598: if (flg4) {
1599: DM fine;
1601: PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine));
1602: PetscCall(PetscViewerPushFormat(viewer, format));
1603: PetscCall(DMLoad(fine, viewer));
1604: PetscCall(PetscViewerDestroy(&viewer));
1605: PetscCall(DMForestSetAdaptivityForest(dm, fine));
1606: PetscCall(DMDestroy(&fine));
1607: PetscCall(DMForestSetTopology(dm, NULL));
1608: PetscCall(DMForestSetBaseDM(dm, NULL));
1609: }
1610: PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
1611: PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0));
1612: if (flg) {
1613: PetscCall(DMForestSetAdjacencyDimension(dm, adjDim));
1614: } else {
1615: PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
1616: PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1));
1617: if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim));
1618: }
1619: PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
1620: PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0));
1621: if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap));
1622: #if 0
1623: PetscCall(PetscOptionsBoundedInt("-dm_refine","equivalent to -dm_forest_set_minimum_refinement and -dm_forest_set_initial_refinement with the same value",NULL,minRefinement,&minRefinement,&flg,0));
1624: if (flg) {
1625: PetscCall(DMForestSetMinimumRefinement(dm,minRefinement));
1626: PetscCall(DMForestSetInitialRefinement(dm,minRefinement));
1627: }
1628: PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0));
1629: if (flg) {
1630: PetscCall(DMForestSetMinimumRefinement(dm,0));
1631: PetscCall(DMForestSetInitialRefinement(dm,initRefinement));
1632: }
1633: #endif
1634: PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement));
1635: PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0));
1636: if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement));
1637: PetscCall(DMForestGetInitialRefinement(dm, &initRefinement));
1638: PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0));
1639: if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement));
1640: PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement));
1641: PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0));
1642: if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement));
1643: PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy));
1644: PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg));
1645: if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer));
1646: PetscCall(DMForestGetGradeFactor(dm, &grade));
1647: PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0));
1648: if (flg) PetscCall(DMForestSetGradeFactor(dm, grade));
1649: PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor));
1650: PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg));
1651: if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor));
1652: PetscOptionsHeadEnd();
1653: PetscFunctionReturn(PETSC_SUCCESS);
1654: }
1656: static PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1657: {
1658: PetscFunctionBegin;
1659: if (subdm) PetscCall(DMClone(dm, subdm));
1660: PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm));
1661: PetscFunctionReturn(PETSC_SUCCESS);
1662: }
1664: static PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
1665: {
1666: DMLabel refine;
1667: DM fineDM;
1669: PetscFunctionBegin;
1670: PetscCall(DMGetFineDM(dm, &fineDM));
1671: if (fineDM) {
1672: PetscCall(PetscObjectReference((PetscObject)fineDM));
1673: *dmRefined = fineDM;
1674: PetscFunctionReturn(PETSC_SUCCESS);
1675: }
1676: PetscCall(DMForestTemplate(dm, comm, dmRefined));
1677: PetscCall(DMGetLabel(dm, "refine", &refine));
1678: if (!refine) {
1679: PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine));
1680: PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE));
1681: } else PetscCall(PetscObjectReference((PetscObject)refine));
1682: PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine));
1683: PetscCall(DMLabelDestroy(&refine));
1684: PetscFunctionReturn(PETSC_SUCCESS);
1685: }
1687: static PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
1688: {
1689: DMLabel coarsen;
1690: DM coarseDM;
1692: PetscFunctionBegin;
1693: if (comm != MPI_COMM_NULL) {
1694: PetscMPIInt mpiComparison;
1695: MPI_Comm dmcomm = PetscObjectComm((PetscObject)dm);
1697: PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison));
1698: PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet");
1699: }
1700: PetscCall(DMGetCoarseDM(dm, &coarseDM));
1701: if (coarseDM) {
1702: PetscCall(PetscObjectReference((PetscObject)coarseDM));
1703: *dmCoarsened = coarseDM;
1704: PetscFunctionReturn(PETSC_SUCCESS);
1705: }
1706: PetscCall(DMForestTemplate(dm, comm, dmCoarsened));
1707: PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN));
1708: PetscCall(DMGetLabel(dm, "coarsen", &coarsen));
1709: if (!coarsen) {
1710: PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
1711: PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
1712: } else PetscCall(PetscObjectReference((PetscObject)coarsen));
1713: PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen));
1714: PetscCall(DMLabelDestroy(&coarsen));
1715: PetscFunctionReturn(PETSC_SUCCESS);
1716: }
1718: PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
1719: {
1720: PetscBool success;
1722: PetscFunctionBegin;
1723: PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM));
1724: PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label));
1725: PetscCall(DMSetUp(*adaptedDM));
1726: PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success));
1727: if (!success) {
1728: PetscCall(DMDestroy(adaptedDM));
1729: *adaptedDM = NULL;
1730: }
1731: PetscFunctionReturn(PETSC_SUCCESS);
1732: }
1734: static PetscErrorCode DMInitialize_Forest(DM dm)
1735: {
1736: PetscFunctionBegin;
1737: PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
1739: dm->ops->clone = DMClone_Forest;
1740: dm->ops->setfromoptions = DMSetFromOptions_Forest;
1741: dm->ops->destroy = DMDestroy_Forest;
1742: dm->ops->createsubdm = DMCreateSubDM_Forest;
1743: dm->ops->refine = DMRefine_Forest;
1744: dm->ops->coarsen = DMCoarsen_Forest;
1745: PetscFunctionReturn(PETSC_SUCCESS);
1746: }
1748: /*MC
1749: DMFOREST = "forest" - A DM object that encapsulates a hierarchically refined mesh. Forests usually have a base `DM`
1750: (see `DMForestGetBaseDM()`), from which it is refined. The refinement and partitioning of forests is considered
1751: immutable after `DMSetUp()` is called. To adapt a mesh, one should call `DMForestTemplate()` to create a new mesh that
1752: will default to being identical to it, specify how that mesh should differ, and then calling `DMSetUp()` on the new
1753: mesh.
1755: To specify that a mesh should be refined or coarsened from the previous mesh, a label should be defined on the
1756: previous mesh whose values indicate which cells should be refined (`DM_ADAPT_REFINE`) or coarsened (`DM_ADAPT_COARSEN`)
1757: and how (subtypes are free to allow additional values for things like anisotropic refinement). The label should be
1758: given to the *new* mesh with `DMForestSetAdaptivityLabel()`.
1760: Level: advanced
1762: .seealso: `DMType`, `DM`, `DMCreate()`, `DMSetType()`, `DMForestGetBaseDM()`, `DMForestSetBaseDM()`, `DMForestTemplate()`, `DMForestSetAdaptivityLabel()`
1763: M*/
1765: PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
1766: {
1767: DM_Forest *forest;
1769: PetscFunctionBegin;
1771: PetscCall(PetscNew(&forest));
1772: dm->dim = 0;
1773: dm->data = forest;
1774: forest->refct = 1;
1775: forest->data = NULL;
1776: forest->topology = NULL;
1777: forest->adapt = NULL;
1778: forest->base = NULL;
1779: forest->adaptPurpose = DM_ADAPT_DETERMINE;
1780: forest->adjDim = PETSC_DEFAULT;
1781: forest->overlap = PETSC_DEFAULT;
1782: forest->minRefinement = PETSC_DEFAULT;
1783: forest->maxRefinement = PETSC_DEFAULT;
1784: forest->initRefinement = PETSC_DEFAULT;
1785: forest->cStart = PETSC_DETERMINE;
1786: forest->cEnd = PETSC_DETERMINE;
1787: forest->cellSF = NULL;
1788: forest->adaptLabel = NULL;
1789: forest->gradeFactor = 2;
1790: forest->cellWeights = NULL;
1791: forest->cellWeightsCopyMode = PETSC_USE_POINTER;
1792: forest->weightsFactor = 1.;
1793: forest->weightCapacity = 1.;
1794: PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL));
1795: PetscCall(DMInitialize_Forest(dm));
1796: PetscFunctionReturn(PETSC_SUCCESS);
1797: }