xref: /petsc/src/dm/impls/forest/forest.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 #include <petsc/private/dmforestimpl.h> /*I "petscdmforest.h" I*/
2 #include <petsc/private/dmimpl.h>       /*I "petscdm.h" I*/
3 #include <petsc/private/dmlabelimpl.h>  /*I "petscdmlabel.h" I*/
4 #include <petscsf.h>
5 
6 PetscBool DMForestPackageInitialized = PETSC_FALSE;
7 
8 typedef struct _DMForestTypeLink *DMForestTypeLink;
9 
10 struct _DMForestTypeLink {
11   char            *name;
12   DMForestTypeLink next;
13 };
14 
15 DMForestTypeLink DMForestTypeList;
16 
17 static PetscErrorCode DMForestPackageFinalize(void)
18 {
19   DMForestTypeLink oldLink, link = DMForestTypeList;
20 
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 }
30 
31 static PetscErrorCode DMForestPackageInitialize(void)
32 {
33   PetscFunctionBegin;
34   if (DMForestPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
35   DMForestPackageInitialized = PETSC_TRUE;
36 
37   PetscCall(DMForestRegisterType(DMFOREST));
38   PetscCall(PetscRegisterFinalize(DMForestPackageFinalize));
39   PetscFunctionReturn(PETSC_SUCCESS);
40 }
41 
42 /*@C
43   DMForestRegisterType - Registers a `DMType` as a subtype of `DMFOREST` (so that `DMIsForest()` will be correct)
44 
45   Not Collective
46 
47   Input Parameter:
48 . name - the name of the type
49 
50   Level: advanced
51 
52 .seealso: `DMFOREST`, `DMIsForest()`
53 @*/
54 PetscErrorCode DMForestRegisterType(DMType name)
55 {
56   DMForestTypeLink link;
57 
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 }
66 
67 /*@
68   DMIsForest - Check whether a DM uses the DMFOREST interface for hierarchically-refined meshes
69 
70   Not Collective
71 
72   Input Parameter:
73 . dm - the DM object
74 
75   Output Parameter:
76 . isForest - whether dm is a subtype of DMFOREST
77 
78   Level: intermediate
79 
80 .seealso: `DMFOREST`, `DMForestRegisterType()`
81 @*/
82 PetscErrorCode DMIsForest(DM dm, PetscBool *isForest)
83 {
84   DMForestTypeLink link = DMForestTypeList;
85 
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 }
99 
100 /*@
101   DMForestTemplate - Create a new `DM` that will be adapted from a source `DM`.
102 
103   Collective
104 
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()`)
108 
109   Output Parameter:
110 . tdm - the new `DM` object
111 
112   Level: intermediate
113 
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()`).
119 
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;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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;
165 
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 }
173 
174 static PetscErrorCode DMInitialize_Forest(DM dm);
175 
176 PETSC_EXTERN PetscErrorCode DMClone_Forest(DM dm, DM *newdm)
177 {
178   DM_Forest  *forest = (DM_Forest *)dm->data;
179   const char *type;
180 
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 }
189 
190 static PetscErrorCode DMDestroy_Forest(DM dm)
191 {
192   DM_Forest *forest = (DM_Forest *)dm->data;
193 
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 }
216 
217 /*@C
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()`.
221 
222   Logically collectiv
223 
224   Input Parameters:
225 + dm       - the forest
226 - topology - the topology of the forest
227 
228   Level: intermediate
229 
230 .seealso: `DM`, `DMFOREST`, `DMForestGetTopology()`, `DMForestSetBaseDM()`
231 @*/
232 PetscErrorCode DMForestSetTopology(DM dm, DMForestTopology topology)
233 {
234   DM_Forest *forest = (DM_Forest *)dm->data;
235 
236   PetscFunctionBegin;
237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
243 
244 /*@C
245   DMForestGetTopology - Get a string describing the topology of a `DMFOREST`.
246 
247   Not Collective
248 
249   Input Parameter:
250 . dm - the forest
251 
252   Output Parameter:
253 . topology - the topology of the forest (e.g., 'cube', 'shell')
254 
255   Level: intermediate
256 
257 .seealso: `DM`, `DMFOREST`, `DMForestSetTopology()`
258 @*/
259 PetscErrorCode DMForestGetTopology(DM dm, DMForestTopology *topology)
260 {
261   DM_Forest *forest = (DM_Forest *)dm->data;
262 
263   PetscFunctionBegin;
264   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
265   PetscAssertPointer(topology, 2);
266   *topology = forest->topology;
267   PetscFunctionReturn(PETSC_SUCCESS);
268 }
269 
270 /*@
271   DMForestSetBaseDM - During the pre-setup phase, set the `DM` that defines the base mesh of a
272   `DMFOREST` forest.
273 
274   Logically Collective
275 
276   Input Parameters:
277 + dm   - the forest
278 - base - the base `DM` of the forest
279 
280   Level: intermediate
281 
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.
286 
287   Currently the base `DM` must be a `DMPLEX`
288 
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;
295 
296   PetscFunctionBegin;
297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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;
304 
305     PetscValidHeaderSpecific(base, DM_CLASSID, 2);
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 }
315 
316 /*@
317   DMForestGetBaseDM - Get the base `DM` of a `DMFOREST`
318 
319   Not Collective
320 
321   Input Parameter:
322 . dm - the forest
323 
324   Output Parameter:
325 . base - the base `DM` of the forest
326 
327   Level: intermediate
328 
329   Notes:
330   After DMSetUp(), the base DM will be redundantly distributed across MPI processes
331 
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.
335 
336 .seealso: `DM`, `DMFOREST`, `DMForestSetBaseDM()`
337 @*/
338 PetscErrorCode DMForestGetBaseDM(DM dm, DM *base)
339 {
340   DM_Forest *forest = (DM_Forest *)dm->data;
341 
342   PetscFunctionBegin;
343   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
344   PetscAssertPointer(base, 2);
345   *base = forest->base;
346   PetscFunctionReturn(PETSC_SUCCESS);
347 }
348 
349 PetscErrorCode DMForestSetBaseCoordinateMapping(DM dm, PetscErrorCode (*func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx)
350 {
351   DM_Forest *forest = (DM_Forest *)dm->data;
352 
353   PetscFunctionBegin;
354   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
355   forest->mapcoordinates    = func;
356   forest->mapcoordinatesctx = ctx;
357   PetscFunctionReturn(PETSC_SUCCESS);
358 }
359 
360 PetscErrorCode DMForestGetBaseCoordinateMapping(DM dm, PetscErrorCode (**func)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *), void *ctx)
361 {
362   DM_Forest *forest = (DM_Forest *)dm->data;
363 
364   PetscFunctionBegin;
365   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
366   if (func) *func = forest->mapcoordinates;
367   if (ctx) *((void **)ctx) = forest->mapcoordinatesctx;
368   PetscFunctionReturn(PETSC_SUCCESS);
369 }
370 
371 /*@
372   DMForestSetAdaptivityForest - During the pre-setup phase, set the forest from which the
373   current forest will be adapted (e.g., the current forest will be
374   refined/coarsened/repartitioned from it) in `DMSetUp()`.
375 
376   Logically Collective
377 
378   Input Parameters:
379 + dm    - the new forest, which will be constructed from adapt
380 - adapt - the old forest
381 
382   Level: intermediate
383 
384   Note:
385   Usually not needed by users directly, `DMForestTemplate()` constructs a new forest to be
386   adapted from an old forest and calls this routine.
387 
388   This can be called after setup with `adapt` = `NULL`, which will clear all internal data
389   related to the adaptivity forest from `dm`. This way, repeatedly adapting does not leave
390   stale `DM` objects in memory.
391 
392 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
393 @*/
394 PetscErrorCode DMForestSetAdaptivityForest(DM dm, DM adapt)
395 {
396   DM_Forest *forest, *adaptForest, *oldAdaptForest;
397   DM         oldAdapt;
398   PetscBool  isForest;
399 
400   PetscFunctionBegin;
401   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
402   if (adapt) PetscValidHeaderSpecific(adapt, DM_CLASSID, 2);
403   PetscCall(DMIsForest(dm, &isForest));
404   if (!isForest) PetscFunctionReturn(PETSC_SUCCESS);
405   PetscCheck(adapt == NULL || !dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
406   forest = (DM_Forest *)dm->data;
407   PetscCall(DMForestGetAdaptivityForest(dm, &oldAdapt));
408   adaptForest    = (DM_Forest *)(adapt ? adapt->data : NULL);
409   oldAdaptForest = (DM_Forest *)(oldAdapt ? oldAdapt->data : NULL);
410   if (adaptForest != oldAdaptForest) {
411     PetscCall(PetscSFDestroy(&forest->preCoarseToFine));
412     PetscCall(PetscSFDestroy(&forest->coarseToPreFine));
413     if (forest->clearadaptivityforest) PetscCall((*forest->clearadaptivityforest)(dm));
414   }
415   switch (forest->adaptPurpose) {
416   case DM_ADAPT_DETERMINE:
417     PetscCall(PetscObjectReference((PetscObject)adapt));
418     PetscCall(DMDestroy(&(forest->adapt)));
419     forest->adapt = adapt;
420     break;
421   case DM_ADAPT_REFINE:
422     PetscCall(DMSetCoarseDM(dm, adapt));
423     break;
424   case DM_ADAPT_COARSEN:
425   case DM_ADAPT_COARSEN_LAST:
426     PetscCall(DMSetFineDM(dm, adapt));
427     break;
428   default:
429     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
430   }
431   PetscFunctionReturn(PETSC_SUCCESS);
432 }
433 
434 /*@
435   DMForestGetAdaptivityForest - Get the forest from which the current forest is adapted.
436 
437   Not Collective
438 
439   Input Parameter:
440 . dm - the forest
441 
442   Output Parameter:
443 . adapt - the forest from which `dm` is/was adapted
444 
445   Level: intermediate
446 
447 .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityForest()`, `DMForestSetAdaptivityPurpose()`
448 @*/
449 PetscErrorCode DMForestGetAdaptivityForest(DM dm, DM *adapt)
450 {
451   DM_Forest *forest;
452 
453   PetscFunctionBegin;
454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
455   forest = (DM_Forest *)dm->data;
456   switch (forest->adaptPurpose) {
457   case DM_ADAPT_DETERMINE:
458     *adapt = forest->adapt;
459     break;
460   case DM_ADAPT_REFINE:
461     PetscCall(DMGetCoarseDM(dm, adapt));
462     break;
463   case DM_ADAPT_COARSEN:
464   case DM_ADAPT_COARSEN_LAST:
465     PetscCall(DMGetFineDM(dm, adapt));
466     break;
467   default:
468     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "invalid adaptivity purpose");
469   }
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 /*@
474   DMForestSetAdaptivityPurpose - During the pre-setup phase, set whether the current `DM` is being adapted from its
475   source (set with `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening
476   (`DM_ADAPT_COARSEN`), or undefined (`DM_ADAPT_DETERMINE`).
477 
478   Logically Collective
479 
480   Input Parameters:
481 + dm      - the forest
482 - purpose - the adaptivity purpose
483 
484   Level: advanced
485 
486   Notes:
487   This only matters for reference counting during `DMDestroy()`. Cyclic references
488   can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
489   (see `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and
490   the user does not maintain a reference to the post-adaptation forest (i.e., the one created
491   by `DMForestTemplate()`), this can cause a memory leak.  This method is used by subtypes
492   of `DMFOREST` when automatically constructing mesh hierarchies.
493 
494 .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
495 @*/
496 PetscErrorCode DMForestSetAdaptivityPurpose(DM dm, DMAdaptFlag purpose)
497 {
498   DM_Forest *forest;
499 
500   PetscFunctionBegin;
501   forest = (DM_Forest *)dm->data;
502   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adaptation forest after setup");
503   if (purpose != forest->adaptPurpose) {
504     DM adapt;
505 
506     PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
507     PetscCall(PetscObjectReference((PetscObject)adapt));
508     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
509 
510     forest->adaptPurpose = purpose;
511 
512     PetscCall(DMForestSetAdaptivityForest(dm, adapt));
513     PetscCall(DMDestroy(&adapt));
514   }
515   PetscFunctionReturn(PETSC_SUCCESS);
516 }
517 
518 /*@
519   DMForestGetAdaptivityPurpose - Get whether the current `DM` is being adapted from its source (set with
520   `DMForestSetAdaptivityForest()`) for the purpose of refinement (`DM_ADAPT_REFINE`), coarsening (`DM_ADAPT_COARSEN`),
521   coarsening only the last level (`DM_ADAPT_COARSEN_LAST`) or undefined (`DM_ADAPT_DETERMINE`).
522 
523   Not Collective
524 
525   Input Parameter:
526 . dm - the forest
527 
528   Output Parameter:
529 . purpose - the adaptivity purpose
530 
531   Level: advanced
532 
533   Notes:
534   This only matters for reference counting: during `DMDestroy()`. Cyclic references
535   can be found between `DM`s only if the cyclic reference is due to a fine/coarse relationship
536   (See `DMSetFineDM()`/`DMSetCoarseDM()`).  If the purpose is not refinement or coarsening, and
537   the user does not maintain a reference to the post-adaptation forest (i.e., the one created
538   by `DMForestTemplate()`), this can cause a memory leak.  This method is used by subtypes
539   of `DMFOREST` when automatically constructing mesh hierarchies.
540 
541 .seealso: `DM`, `DMFOREST`, `DMForestTemplate()`, `DMForestSetAdaptivityForest()`, `DMForestGetAdaptivityForest()`, `DMAdaptFlag`
542 @*/
543 PetscErrorCode DMForestGetAdaptivityPurpose(DM dm, DMAdaptFlag *purpose)
544 {
545   DM_Forest *forest;
546 
547   PetscFunctionBegin;
548   forest   = (DM_Forest *)dm->data;
549   *purpose = forest->adaptPurpose;
550   PetscFunctionReturn(PETSC_SUCCESS);
551 }
552 
553 /*@
554   DMForestSetAdjacencyDimension - During the pre-setup phase, set the dimension of interface points that determine
555   cell adjacency (for the purposes of partitioning and overlap).
556 
557   Logically Collective
558 
559   Input Parameters:
560 + dm     - the forest
561 - adjDim - default 0 (i.e., vertices determine adjacency)
562 
563   Level: intermediate
564 
565 .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
566 @*/
567 PetscErrorCode DMForestSetAdjacencyDimension(DM dm, PetscInt adjDim)
568 {
569   PetscInt   dim;
570   DM_Forest *forest = (DM_Forest *)dm->data;
571 
572   PetscFunctionBegin;
573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
574   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the adjacency dimension after setup");
575   PetscCheck(adjDim >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be < 0: %" PetscInt_FMT, adjDim);
576   PetscCall(DMGetDimension(dm, &dim));
577   PetscCheck(adjDim <= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "adjacency dim cannot be > %" PetscInt_FMT ": %" PetscInt_FMT, dim, adjDim);
578   forest->adjDim = adjDim;
579   PetscFunctionReturn(PETSC_SUCCESS);
580 }
581 
582 /*@
583   DMForestSetAdjacencyCodimension - Like `DMForestSetAdjacencyDimension()`, but specified as a co-dimension (so that,
584   e.g., adjacency based on facets can be specified by codimension 1 in all cases)
585 
586   Logically Collective
587 
588   Input Parameters:
589 + dm       - the forest
590 - adjCodim - default is the dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices
591 
592   Level: intermediate
593 
594 .seealso: `DM`, `DMFOREST`, `DMForestGetAdjacencyCodimension()`, `DMForestSetAdjacencyDimension()`
595 @*/
596 PetscErrorCode DMForestSetAdjacencyCodimension(DM dm, PetscInt adjCodim)
597 {
598   PetscInt dim;
599 
600   PetscFunctionBegin;
601   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
602   PetscCall(DMGetDimension(dm, &dim));
603   PetscCall(DMForestSetAdjacencyDimension(dm, dim - adjCodim));
604   PetscFunctionReturn(PETSC_SUCCESS);
605 }
606 
607 /*@
608   DMForestGetAdjacencyDimension - Get the dimension of interface points that determine cell adjacency (for the
609   purposes of partitioning and overlap).
610 
611   Not Collective
612 
613   Input Parameter:
614 . dm - the forest
615 
616   Output Parameter:
617 . adjDim - default 0 (i.e., vertices determine adjacency)
618 
619   Level: intermediate
620 
621 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestGetAdjacencyCodimension()`, `DMForestSetPartitionOverlap()`
622 @*/
623 PetscErrorCode DMForestGetAdjacencyDimension(DM dm, PetscInt *adjDim)
624 {
625   DM_Forest *forest = (DM_Forest *)dm->data;
626 
627   PetscFunctionBegin;
628   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
629   PetscAssertPointer(adjDim, 2);
630   *adjDim = forest->adjDim;
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@
635   DMForestGetAdjacencyCodimension - Like `DMForestGetAdjacencyDimension()`, but specified as a co-dimension (so that,
636   e.g., adjacency based on facets can be specified by codimension 1 in all cases)
637 
638   Not Collective
639 
640   Input Parameter:
641 . dm - the forest
642 
643   Output Parameter:
644 . adjCodim - default isthe dimension of the forest (see `DMGetDimension()`), since this is the codimension of vertices
645 
646   Level: intermediate
647 
648 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyCodimension()`, `DMForestGetAdjacencyDimension()`
649 @*/
650 PetscErrorCode DMForestGetAdjacencyCodimension(DM dm, PetscInt *adjCodim)
651 {
652   DM_Forest *forest = (DM_Forest *)dm->data;
653   PetscInt   dim;
654 
655   PetscFunctionBegin;
656   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
657   PetscAssertPointer(adjCodim, 2);
658   PetscCall(DMGetDimension(dm, &dim));
659   *adjCodim = dim - forest->adjDim;
660   PetscFunctionReturn(PETSC_SUCCESS);
661 }
662 
663 /*@
664   DMForestSetPartitionOverlap - During the pre-setup phase, set the amount of cell-overlap present in parallel
665   partitions of a forest, with values > 0 indicating subdomains that are expanded by that many iterations of adding
666   adjacent cells
667 
668   Logically Collective
669 
670   Input Parameters:
671 + dm      - the forest
672 - overlap - default 0
673 
674   Level: intermediate
675 
676 .seealso: `DM`, `DMFOREST`, `DMForestGetPartitionOverlap()`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
677 @*/
678 PetscErrorCode DMForestSetPartitionOverlap(DM dm, PetscInt overlap)
679 {
680   DM_Forest *forest = (DM_Forest *)dm->data;
681 
682   PetscFunctionBegin;
683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
684   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the overlap after setup");
685   PetscCheck(overlap >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "overlap cannot be < 0: %" PetscInt_FMT, overlap);
686   forest->overlap = overlap;
687   PetscFunctionReturn(PETSC_SUCCESS);
688 }
689 
690 /*@
691   DMForestGetPartitionOverlap - Get the amount of cell-overlap present in parallel partitions of a forest, with values
692   > 0 indicating subdomains that are expanded by that many iterations of adding adjacent cells
693 
694   Not Collective
695 
696   Input Parameter:
697 . dm - the forest
698 
699   Output Parameter:
700 . overlap - default 0
701 
702   Level: intermediate
703 
704 .seealso: `DM`, `DMFOREST`, `DMForestSetAdjacencyDimension()`, `DMForestSetAdjacencyCodimension()`
705 @*/
706 PetscErrorCode DMForestGetPartitionOverlap(DM dm, PetscInt *overlap)
707 {
708   DM_Forest *forest = (DM_Forest *)dm->data;
709 
710   PetscFunctionBegin;
711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
712   PetscAssertPointer(overlap, 2);
713   *overlap = forest->overlap;
714   PetscFunctionReturn(PETSC_SUCCESS);
715 }
716 
717 /*@
718   DMForestSetMinimumRefinement - During the pre-setup phase, set the minimum level of refinement (relative to the base
719   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by coarsening a previous forest
720   (see `DMForestGetAdaptivityForest()`) this limits the amount of coarsening.
721 
722   Logically Collective
723 
724   Input Parameters:
725 + dm            - the forest
726 - minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
727 
728   Level: intermediate
729 
730 .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
731 @*/
732 PetscErrorCode DMForestSetMinimumRefinement(DM dm, PetscInt minRefinement)
733 {
734   DM_Forest *forest = (DM_Forest *)dm->data;
735 
736   PetscFunctionBegin;
737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
738   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the minimum refinement after setup");
739   forest->minRefinement = minRefinement;
740   PetscFunctionReturn(PETSC_SUCCESS);
741 }
742 
743 /*@
744   DMForestGetMinimumRefinement - Get the minimum level of refinement (relative to the base `DM`, see
745   `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by coarsening a previous forest (see
746   `DMForestGetAdaptivityForest()`), this limits the amount of coarsening.
747 
748   Not Collective
749 
750   Input Parameter:
751 . dm - the forest
752 
753   Output Parameter:
754 . minRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
755 
756   Level: intermediate
757 
758 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestGetMaximumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
759 @*/
760 PetscErrorCode DMForestGetMinimumRefinement(DM dm, PetscInt *minRefinement)
761 {
762   DM_Forest *forest = (DM_Forest *)dm->data;
763 
764   PetscFunctionBegin;
765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
766   PetscAssertPointer(minRefinement, 2);
767   *minRefinement = forest->minRefinement;
768   PetscFunctionReturn(PETSC_SUCCESS);
769 }
770 
771 /*@
772   DMForestSetInitialRefinement - During the pre-setup phase, set the initial level of refinement (relative to the base
773   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.
774 
775   Logically Collective
776 
777   Input Parameters:
778 + dm             - the forest
779 - initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
780 
781   Level: intermediate
782 
783 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
784 @*/
785 PetscErrorCode DMForestSetInitialRefinement(DM dm, PetscInt initRefinement)
786 {
787   DM_Forest *forest = (DM_Forest *)dm->data;
788 
789   PetscFunctionBegin;
790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
791   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the initial refinement after setup");
792   forest->initRefinement = initRefinement;
793   PetscFunctionReturn(PETSC_SUCCESS);
794 }
795 
796 /*@
797   DMForestGetInitialRefinement - Get the initial level of refinement (relative to the base `DM`, see
798   `DMForestGetBaseDM()`) allowed in the forest.
799 
800   Not Collective
801 
802   Input Parameter:
803 . dm - the forest
804 
805   Output Parameter:
806 . initRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
807 
808   Level: intermediate
809 
810 .seealso: `DM`, `DMFOREST`, `DMForestSetMinimumRefinement()`, `DMForestSetMaximumRefinement()`, `DMForestGetBaseDM()`
811 @*/
812 PetscErrorCode DMForestGetInitialRefinement(DM dm, PetscInt *initRefinement)
813 {
814   DM_Forest *forest = (DM_Forest *)dm->data;
815 
816   PetscFunctionBegin;
817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
818   PetscAssertPointer(initRefinement, 2);
819   *initRefinement = forest->initRefinement;
820   PetscFunctionReturn(PETSC_SUCCESS);
821 }
822 
823 /*@
824   DMForestSetMaximumRefinement - During the pre-setup phase, set the maximum level of refinement (relative to the base
825   `DM`, see `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by refining a previous forest
826   (see `DMForestGetAdaptivityForest()`), this limits the amount of refinement.
827 
828   Logically Collective
829 
830   Input Parameters:
831 + dm            - the forest
832 - maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
833 
834   Level: intermediate
835 
836 .seealso: `DM`, `DMFOREST`, `DMForestGetMinimumRefinement()`, `DMForestSetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityDM()`
837 @*/
838 PetscErrorCode DMForestSetMaximumRefinement(DM dm, PetscInt maxRefinement)
839 {
840   DM_Forest *forest = (DM_Forest *)dm->data;
841 
842   PetscFunctionBegin;
843   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
844   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the maximum refinement after setup");
845   forest->maxRefinement = maxRefinement;
846   PetscFunctionReturn(PETSC_SUCCESS);
847 }
848 
849 /*@
850   DMForestGetMaximumRefinement - Get the maximum level of refinement (relative to the base `DM`, see
851   `DMForestGetBaseDM()`) allowed in the forest.  If the forest is being created by refining a previous forest (see
852   `DMForestGetAdaptivityForest()`), this limits the amount of refinement.
853 
854   Not Collective
855 
856   Input Parameter:
857 . dm - the forest
858 
859   Output Parameter:
860 . maxRefinement - default `PETSC_DEFAULT` (interpreted by the subtype of `DMFOREST`)
861 
862   Level: intermediate
863 
864 .seealso: `DM`, `DMFOREST`, `DMForestSetMaximumRefinement()`, `DMForestGetMinimumRefinement()`, `DMForestGetInitialRefinement()`, `DMForestGetBaseDM()`, `DMForestGetAdaptivityForest()`
865 @*/
866 PetscErrorCode DMForestGetMaximumRefinement(DM dm, PetscInt *maxRefinement)
867 {
868   DM_Forest *forest = (DM_Forest *)dm->data;
869 
870   PetscFunctionBegin;
871   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
872   PetscAssertPointer(maxRefinement, 2);
873   *maxRefinement = forest->maxRefinement;
874   PetscFunctionReturn(PETSC_SUCCESS);
875 }
876 
877 /*@C
878   DMForestSetAdaptivityStrategy - During the pre-setup phase, set the strategy for combining adaptivity labels from multiple processes.
879 
880   Logically Collective
881 
882   Input Parameters:
883 + dm            - the forest
884 - adaptStrategy - default `DMFORESTADAPTALL`
885 
886   Level: advanced
887 
888   Notes:
889   Subtypes of `DMFOREST` may define their own strategies.  Two default strategies are `DMFORESTADAPTALL`, which indicates that all processes must agree
890   for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only one process needs to
891   specify refinement/coarsening.
892 
893 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityStrategy()`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`
894 @*/
895 PetscErrorCode DMForestSetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy adaptStrategy)
896 {
897   DM_Forest *forest = (DM_Forest *)dm->data;
898 
899   PetscFunctionBegin;
900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
901   PetscCall(PetscFree(forest->adaptStrategy));
902   PetscCall(PetscStrallocpy((const char *)adaptStrategy, (char **)&forest->adaptStrategy));
903   PetscFunctionReturn(PETSC_SUCCESS);
904 }
905 
906 /*@C
907   DMForestGetAdaptivityStrategy - Get the strategy for combining adaptivity labels from multiple processes.
908 
909   Not Collective
910 
911   Input Parameter:
912 . dm - the forest
913 
914   Output Parameter:
915 . adaptStrategy - the adaptivity strategy (default `DMFORESTADAPTALL`)
916 
917   Level: advanced
918 
919   Note:
920   Subtypes
921   of `DMFOREST` may define their own strategies.  Two default strategies are `DMFORESTADAPTALL`, which indicates that all
922   processes must agree for a refinement/coarsening flag to be valid, and `DMFORESTADAPTANY`, which indicates that only
923   one process needs to specify refinement/coarsening.
924 
925 .seealso: `DM`, `DMFOREST`, `DMFORESTADAPTALL`, `DMFORESTADAPTANY`, `DMForestSetAdaptivityStrategy()`
926 @*/
927 PetscErrorCode DMForestGetAdaptivityStrategy(DM dm, DMForestAdaptivityStrategy *adaptStrategy)
928 {
929   DM_Forest *forest = (DM_Forest *)dm->data;
930 
931   PetscFunctionBegin;
932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
933   PetscAssertPointer(adaptStrategy, 2);
934   *adaptStrategy = forest->adaptStrategy;
935   PetscFunctionReturn(PETSC_SUCCESS);
936 }
937 
938 /*@
939   DMForestGetAdaptivitySuccess - Return whether the requested adaptation (refinement, coarsening, repartitioning,
940   etc.) was successful.
941 
942   Collective
943 
944   Input Parameter:
945 . dm - the post-adaptation forest
946 
947   Output Parameter:
948 . success - `PETSC_TRUE` if the post-adaptation forest is different from the pre-adaptation forest.
949 
950   Level: intermediate
951 
952   Notes:
953   `PETSC_FALSE` indicates that the post-adaptation forest is the same as the pre-adaptation
954   forest.  A requested adaptation may have been unsuccessful if, for example, the requested refinement would have
955   exceeded the maximum refinement level.
956 
957 .seealso: `DM`, `DMFOREST`
958 @*/
959 PetscErrorCode DMForestGetAdaptivitySuccess(DM dm, PetscBool *success)
960 {
961   DM_Forest *forest;
962 
963   PetscFunctionBegin;
964   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
965   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMSetUp() has not been called yet.");
966   forest = (DM_Forest *)dm->data;
967   PetscCall((forest->getadaptivitysuccess)(dm, success));
968   PetscFunctionReturn(PETSC_SUCCESS);
969 }
970 
971 /*@
972   DMForestSetComputeAdaptivitySF - During the pre-setup phase, set whether transfer `PetscSF`s should be computed
973   relating the cells of the pre-adaptation forest to the post-adaptiation forest.
974 
975   Logically Collective
976 
977   Input Parameters:
978 + dm        - the post-adaptation forest
979 - computeSF - default `PETSC_TRUE`
980 
981   Level: advanced
982 
983   Note:
984   After `DMSetUp()` is called, the transfer `PetscSF`s can be accessed with `DMForestGetAdaptivitySF()`.
985 
986 .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
987 @*/
988 PetscErrorCode DMForestSetComputeAdaptivitySF(DM dm, PetscBool computeSF)
989 {
990   DM_Forest *forest;
991 
992   PetscFunctionBegin;
993   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
994   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot compute adaptivity PetscSFs after setup is called");
995   forest                 = (DM_Forest *)dm->data;
996   forest->computeAdaptSF = computeSF;
997   PetscFunctionReturn(PETSC_SUCCESS);
998 }
999 
1000 PetscErrorCode DMForestTransferVec(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
1001 {
1002   DM_Forest *forest;
1003 
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(dmIn, DM_CLASSID, 1);
1006   PetscValidHeaderSpecific(vecIn, VEC_CLASSID, 2);
1007   PetscValidHeaderSpecific(dmOut, DM_CLASSID, 3);
1008   PetscValidHeaderSpecific(vecOut, VEC_CLASSID, 4);
1009   forest = (DM_Forest *)dmIn->data;
1010   PetscCheck(forest->transfervec, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "DMForestTransferVec() not implemented");
1011   PetscCall((forest->transfervec)(dmIn, vecIn, dmOut, vecOut, useBCs, time));
1012   PetscFunctionReturn(PETSC_SUCCESS);
1013 }
1014 
1015 PetscErrorCode DMForestTransferVecFromBase(DM dm, Vec vecIn, Vec vecOut)
1016 {
1017   DM_Forest *forest;
1018 
1019   PetscFunctionBegin;
1020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1021   PetscValidHeaderSpecific(vecIn, VEC_CLASSID, 2);
1022   PetscValidHeaderSpecific(vecOut, VEC_CLASSID, 3);
1023   forest = (DM_Forest *)dm->data;
1024   PetscCheck(forest->transfervecfrombase, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMForestTransferVecFromBase() not implemented");
1025   PetscCall((forest->transfervecfrombase)(dm, vecIn, vecOut));
1026   PetscFunctionReturn(PETSC_SUCCESS);
1027 }
1028 
1029 /*@
1030   DMForestGetComputeAdaptivitySF - Get whether transfer `PetscSF`s should be computed relating the cells of the
1031   pre-adaptation forest to the post-adaptiation forest.  After `DMSetUp()` is called, these transfer PetscSFs can be
1032   accessed with `DMForestGetAdaptivitySF()`.
1033 
1034   Not Collective
1035 
1036   Input Parameter:
1037 . dm - the post-adaptation forest
1038 
1039   Output Parameter:
1040 . computeSF - default `PETSC_TRUE`
1041 
1042   Level: advanced
1043 
1044 .seealso: `DM`, `DMFOREST`, `DMForestSetComputeAdaptivitySF()`, `DMForestGetAdaptivitySF()`
1045 @*/
1046 PetscErrorCode DMForestGetComputeAdaptivitySF(DM dm, PetscBool *computeSF)
1047 {
1048   DM_Forest *forest;
1049 
1050   PetscFunctionBegin;
1051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1052   forest     = (DM_Forest *)dm->data;
1053   *computeSF = forest->computeAdaptSF;
1054   PetscFunctionReturn(PETSC_SUCCESS);
1055 }
1056 
1057 /*@
1058   DMForestGetAdaptivitySF - Get `PetscSF`s that relate the pre-adaptation forest to the
1059   post-adaptation forest.
1060 
1061   Not Collective
1062 
1063   Input Parameter:
1064 . dm - the post-adaptation forest
1065 
1066   Output Parameters:
1067 + preCoarseToFine - pre-adaptation coarse cells to post-adaptation fine cells: BCast goes from pre- to post-
1068 - coarseToPreFine - post-adaptation coarse cells to pre-adaptation fine cells: BCast goes from post- to pre-
1069 
1070   Level: advanced
1071 
1072   Notes:
1073   Adaptation can be any combination of refinement, coarsening, repartition, and change of
1074   overlap, so there may be some cells of the pre-adaptation that are parents of post-adaptation
1075   cells, and vice versa.  Therefore there are two `PetscSF`s: one that relates pre-adaptation
1076   coarse cells to post-adaptation fine cells, and one that relates pre-adaptation fine cells to
1077   post-adaptation coarse cells.
1078 
1079 .seealso: `DM`, `DMFOREST`, `DMForestGetComputeAdaptivitySF()`, `DMForestSetComputeAdaptivitySF()`
1080 @*/
1081 PetscErrorCode DMForestGetAdaptivitySF(DM dm, PetscSF *preCoarseToFine, PetscSF *coarseToPreFine)
1082 {
1083   DM_Forest *forest;
1084 
1085   PetscFunctionBegin;
1086   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1087   PetscCall(DMSetUp(dm));
1088   forest = (DM_Forest *)dm->data;
1089   if (preCoarseToFine) *preCoarseToFine = forest->preCoarseToFine;
1090   if (coarseToPreFine) *coarseToPreFine = forest->coarseToPreFine;
1091   PetscFunctionReturn(PETSC_SUCCESS);
1092 }
1093 
1094 /*@
1095   DMForestSetGradeFactor - During the pre-setup phase, set the desired amount of grading in the
1096   mesh, e.g. give 2 to indicate that the diameter of neighboring cells should differ by at most
1097   a factor of 2.
1098 
1099   Logically Collective
1100 
1101   Input Parameters:
1102 + dm    - the forest
1103 - grade - the grading factor
1104 
1105   Level: advanced
1106 
1107   Note:
1108   Subtypes of `DMFOREST` may only support one particular choice of grading factor.
1109 
1110 .seealso: `DM`, `DMFOREST`, `DMForestGetGradeFactor()`
1111 @*/
1112 PetscErrorCode DMForestSetGradeFactor(DM dm, PetscInt grade)
1113 {
1114   DM_Forest *forest = (DM_Forest *)dm->data;
1115 
1116   PetscFunctionBegin;
1117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1118   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the grade factor after setup");
1119   forest->gradeFactor = grade;
1120   PetscFunctionReturn(PETSC_SUCCESS);
1121 }
1122 
1123 /*@
1124   DMForestGetGradeFactor - Get the desired amount of grading in the mesh, e.g. give 2 to indicate that the diameter of
1125   neighboring cells should differ by at most a factor of 2.  Subtypes of `DMFOREST` may only support one particular
1126   choice of grading factor.
1127 
1128   Not Collective
1129 
1130   Input Parameter:
1131 . dm - the forest
1132 
1133   Output Parameter:
1134 . grade - the grading factor
1135 
1136   Level: advanced
1137 
1138 .seealso: `DM`, `DMFOREST`, `DMForestSetGradeFactor()`
1139 @*/
1140 PetscErrorCode DMForestGetGradeFactor(DM dm, PetscInt *grade)
1141 {
1142   DM_Forest *forest = (DM_Forest *)dm->data;
1143 
1144   PetscFunctionBegin;
1145   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1146   PetscAssertPointer(grade, 2);
1147   *grade = forest->gradeFactor;
1148   PetscFunctionReturn(PETSC_SUCCESS);
1149 }
1150 
1151 /*@
1152   DMForestSetCellWeightFactor - During the pre-setup phase, set the factor by which the level of refinement changes
1153   the cell weight (see `DMForestSetCellWeights()`) when calculating partitions.
1154 
1155   Logically Collective
1156 
1157   Input Parameters:
1158 + dm            - the forest
1159 - weightsFactor - default 1.
1160 
1161   Level: advanced
1162 
1163   Note:
1164   The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel).  A factor
1165   of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
1166   example, might be appropriate for sub-cycling time-stepping methods, when the computation
1167   associated with a cell is multiplied by a factor of 2 for each additional level of
1168   refinement.
1169 
1170 .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeightFactor()`, `DMForestSetCellWeights()`
1171 @*/
1172 PetscErrorCode DMForestSetCellWeightFactor(DM dm, PetscReal weightsFactor)
1173 {
1174   DM_Forest *forest = (DM_Forest *)dm->data;
1175 
1176   PetscFunctionBegin;
1177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1178   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weights factor after setup");
1179   forest->weightsFactor = weightsFactor;
1180   PetscFunctionReturn(PETSC_SUCCESS);
1181 }
1182 
1183 /*@
1184   DMForestGetCellWeightFactor - Get the factor by which the level of refinement changes the cell weight (see
1185   `DMForestSetCellWeights()`) when calculating partitions.
1186 
1187   Not Collective
1188 
1189   Input Parameter:
1190 . dm - the forest
1191 
1192   Output Parameter:
1193 . weightsFactor - default 1.
1194 
1195   Level: advanced
1196 
1197   Note:
1198   The final weight of a cell will be (cellWeight) * (weightFactor^refinementLevel).  A factor
1199   of 1 indicates that the weight of a cell does not depend on its level; a factor of 2, for
1200   example, might be appropriate for sub-cycling time-stepping methods, when the computation
1201   associated with a cell is multiplied by a factor of 2 for each additional level of
1202   refinement.
1203 
1204 .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeightFactor()`, `DMForestSetCellWeights()`
1205 @*/
1206 PetscErrorCode DMForestGetCellWeightFactor(DM dm, PetscReal *weightsFactor)
1207 {
1208   DM_Forest *forest = (DM_Forest *)dm->data;
1209 
1210   PetscFunctionBegin;
1211   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1212   PetscAssertPointer(weightsFactor, 2);
1213   *weightsFactor = forest->weightsFactor;
1214   PetscFunctionReturn(PETSC_SUCCESS);
1215 }
1216 
1217 /*@
1218   DMForestGetCellChart - After the setup phase, get the local half-open interval of the chart of cells on this process
1219 
1220   Not Collective
1221 
1222   Input Parameter:
1223 . dm - the forest
1224 
1225   Output Parameters:
1226 + cStart - the first cell on this process
1227 - cEnd   - one after the final cell on this process
1228 
1229   Level: intermediate
1230 
1231 .seealso: `DM`, `DMFOREST`, `DMForestGetCellSF()`
1232 @*/
1233 PetscErrorCode DMForestGetCellChart(DM dm, PetscInt *cStart, PetscInt *cEnd)
1234 {
1235   DM_Forest *forest = (DM_Forest *)dm->data;
1236 
1237   PetscFunctionBegin;
1238   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1239   PetscAssertPointer(cStart, 2);
1240   PetscAssertPointer(cEnd, 3);
1241   if (((forest->cStart == PETSC_DETERMINE) || (forest->cEnd == PETSC_DETERMINE)) && forest->createcellchart) PetscCall(forest->createcellchart(dm, &forest->cStart, &forest->cEnd));
1242   *cStart = forest->cStart;
1243   *cEnd   = forest->cEnd;
1244   PetscFunctionReturn(PETSC_SUCCESS);
1245 }
1246 
1247 /*@
1248   DMForestGetCellSF - After the setup phase, get the `PetscSF` for overlapping cells between processes
1249 
1250   Not Collective
1251 
1252   Input Parameter:
1253 . dm - the forest
1254 
1255   Output Parameter:
1256 . cellSF - the `PetscSF`
1257 
1258   Level: intermediate
1259 
1260 .seealso: `DM`, `DMFOREST`, `DMForestGetCellChart()`
1261 @*/
1262 PetscErrorCode DMForestGetCellSF(DM dm, PetscSF *cellSF)
1263 {
1264   DM_Forest *forest = (DM_Forest *)dm->data;
1265 
1266   PetscFunctionBegin;
1267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1268   PetscAssertPointer(cellSF, 2);
1269   if ((!forest->cellSF) && forest->createcellsf) PetscCall(forest->createcellsf(dm, &forest->cellSF));
1270   *cellSF = forest->cellSF;
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 /*@C
1275   DMForestSetAdaptivityLabel - During the pre-setup phase, set the label of the pre-adaptation forest (see
1276   `DMForestGetAdaptivityForest()`) that holds the adaptation flags (refinement, coarsening, or some combination).
1277 
1278   Logically Collective
1279 
1280   Input Parameters:
1281 + dm         - the forest
1282 - adaptLabel - the label in the pre-adaptation forest
1283 
1284   Level: intermediate
1285 
1286   Note:
1287   The interpretation of the label values is up to the subtype of `DMFOREST`, but
1288   `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
1289   reserved as choices that should be accepted by all subtypes.
1290 
1291 .seealso: `DM`, `DMFOREST`, `DMForestGetAdaptivityLabel()`
1292 @*/
1293 PetscErrorCode DMForestSetAdaptivityLabel(DM dm, DMLabel adaptLabel)
1294 {
1295   DM_Forest *forest = (DM_Forest *)dm->data;
1296 
1297   PetscFunctionBegin;
1298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1299   if (adaptLabel) PetscValidHeaderSpecific(adaptLabel, DMLABEL_CLASSID, 2);
1300   PetscCall(PetscObjectReference((PetscObject)adaptLabel));
1301   PetscCall(DMLabelDestroy(&forest->adaptLabel));
1302   forest->adaptLabel = adaptLabel;
1303   PetscFunctionReturn(PETSC_SUCCESS);
1304 }
1305 
1306 /*@C
1307   DMForestGetAdaptivityLabel - Get the label of the pre-adaptation forest (see `DMForestGetAdaptivityForest()`) that
1308   holds the adaptation flags (refinement, coarsening, or some combination).
1309 
1310   Not Collective
1311 
1312   Input Parameter:
1313 . dm - the forest
1314 
1315   Output Parameter:
1316 . adaptLabel - the name of the label in the pre-adaptation forest
1317 
1318   Level: intermediate
1319 
1320   Note:
1321   The interpretation of the label values is up to the subtype of `DMFOREST`, but
1322   `DM_ADAPT_DETERMINE`, `DM_ADAPT_KEEP`, `DM_ADAPT_REFINE`, and `DM_ADAPT_COARSEN` have been
1323   reserved as choices that should be accepted by all subtypes.
1324 
1325 .seealso: `DM`, `DMFOREST`, `DMForestSetAdaptivityLabel()`
1326 @*/
1327 PetscErrorCode DMForestGetAdaptivityLabel(DM dm, DMLabel *adaptLabel)
1328 {
1329   DM_Forest *forest = (DM_Forest *)dm->data;
1330 
1331   PetscFunctionBegin;
1332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1333   *adaptLabel = forest->adaptLabel;
1334   PetscFunctionReturn(PETSC_SUCCESS);
1335 }
1336 
1337 /*@
1338   DMForestSetCellWeights - Set the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
1339   process: weights are used to determine parallel partitioning.
1340 
1341   Logically Collective
1342 
1343   Input Parameters:
1344 + dm       - the forest
1345 . weights  - the array of weights (see `DMForestSetWeightCapacity()`) for all cells, or `NULL` to indicate each cell has weight 1.
1346 - copyMode - how weights should reference weights
1347 
1348   Level: advanced
1349 
1350 .seealso: `DM`, `DMFOREST`, `DMForestGetCellWeights()`, `DMForestSetWeightCapacity()`
1351 @*/
1352 PetscErrorCode DMForestSetCellWeights(DM dm, PetscReal weights[], PetscCopyMode copyMode)
1353 {
1354   DM_Forest *forest = (DM_Forest *)dm->data;
1355   PetscInt   cStart, cEnd;
1356 
1357   PetscFunctionBegin;
1358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1359   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
1360   PetscCheck(cEnd >= cStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cell chart [%" PetscInt_FMT ",%" PetscInt_FMT ") is not valid", cStart, cEnd);
1361   if (copyMode == PETSC_COPY_VALUES) {
1362     if (forest->cellWeightsCopyMode != PETSC_OWN_POINTER || forest->cellWeights == weights) PetscCall(PetscMalloc1(cEnd - cStart, &forest->cellWeights));
1363     PetscCall(PetscArraycpy(forest->cellWeights, weights, cEnd - cStart));
1364     forest->cellWeightsCopyMode = PETSC_OWN_POINTER;
1365     PetscFunctionReturn(PETSC_SUCCESS);
1366   }
1367   if (forest->cellWeightsCopyMode == PETSC_OWN_POINTER) PetscCall(PetscFree(forest->cellWeights));
1368   forest->cellWeights         = weights;
1369   forest->cellWeightsCopyMode = copyMode;
1370   PetscFunctionReturn(PETSC_SUCCESS);
1371 }
1372 
1373 /*@
1374   DMForestGetCellWeights - Get the weights assigned to each of the cells (see `DMForestGetCellChart()`) of the current
1375   process: weights are used to determine parallel partitioning.
1376 
1377   Not Collective
1378 
1379   Input Parameter:
1380 . dm - the forest
1381 
1382   Output Parameter:
1383 . weights - the array of weights for all cells, or `NULL` to indicate each cell has weight 1.
1384 
1385   Level: advanced
1386 
1387 .seealso: `DM`, `DMFOREST`, `DMForestSetCellWeights()`, `DMForestSetWeightCapacity()`
1388 @*/
1389 PetscErrorCode DMForestGetCellWeights(DM dm, PetscReal **weights)
1390 {
1391   DM_Forest *forest = (DM_Forest *)dm->data;
1392 
1393   PetscFunctionBegin;
1394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1395   PetscAssertPointer(weights, 2);
1396   *weights = forest->cellWeights;
1397   PetscFunctionReturn(PETSC_SUCCESS);
1398 }
1399 
1400 /*@
1401   DMForestSetWeightCapacity - During the pre-setup phase, set the capacity of the current process when repartitioning
1402   a pre-adaptation forest (see `DMForestGetAdaptivityForest()`).
1403 
1404   Logically Collective
1405 
1406   Input Parameters:
1407 + dm       - the forest
1408 - capacity - this process's capacity
1409 
1410   Level: advanced
1411 
1412   Note:
1413   After partitioning, the ratio of the weight of each process's cells to the process's capacity
1414   will be roughly equal for all processes.  A capacity of 0 indicates that the current process
1415   should not have any cells after repartitioning.
1416 
1417 .seealso: `DM`, `DMFOREST`, `DMForestGetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1418 @*/
1419 PetscErrorCode DMForestSetWeightCapacity(DM dm, PetscReal capacity)
1420 {
1421   DM_Forest *forest = (DM_Forest *)dm->data;
1422 
1423   PetscFunctionBegin;
1424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1425   PetscCheck(!dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot change the weight capacity after setup");
1426   PetscCheck(capacity >= 0., PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have negative weight capacity; %g", (double)capacity);
1427   forest->weightCapacity = capacity;
1428   PetscFunctionReturn(PETSC_SUCCESS);
1429 }
1430 
1431 /*@
1432   DMForestGetWeightCapacity - Set the capacity of the current process when repartitioning a pre-adaptation forest (see
1433   `DMForestGetAdaptivityForest()`).
1434 
1435   Not Collective
1436 
1437   Input Parameter:
1438 . dm - the forest
1439 
1440   Output Parameter:
1441 . capacity - this process's capacity
1442 
1443   Level: advanced
1444 
1445   Note:
1446   After partitioning, the ratio of the weight of each process's cells to the process's capacity
1447   will be roughly equal for all processes.  A capacity of 0 indicates that the current process
1448   should not have any cells after repartitioning.
1449 
1450 .seealso: `DM`, `DMFOREST`, `DMForestSetWeightCapacity()`, `DMForestSetCellWeights()`, `DMForestSetCellWeightFactor()`
1451 @*/
1452 PetscErrorCode DMForestGetWeightCapacity(DM dm, PetscReal *capacity)
1453 {
1454   DM_Forest *forest = (DM_Forest *)dm->data;
1455 
1456   PetscFunctionBegin;
1457   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1458   PetscAssertPointer(capacity, 2);
1459   *capacity = forest->weightCapacity;
1460   PetscFunctionReturn(PETSC_SUCCESS);
1461 }
1462 
1463 PETSC_EXTERN PetscErrorCode DMSetFromOptions_Forest(DM dm, PetscOptionItems *PetscOptionsObject)
1464 {
1465   PetscBool                  flg, flg1, flg2, flg3, flg4;
1466   DMForestTopology           oldTopo;
1467   char                       stringBuffer[256];
1468   PetscViewer                viewer;
1469   PetscViewerFormat          format;
1470   PetscInt                   adjDim, adjCodim, overlap, minRefinement, initRefinement, maxRefinement, grade;
1471   PetscReal                  weightsFactor;
1472   DMForestAdaptivityStrategy adaptStrategy;
1473 
1474   PetscFunctionBegin;
1475   PetscCall(DMForestGetTopology(dm, &oldTopo));
1476   PetscOptionsHeadBegin(PetscOptionsObject, "DMForest Options");
1477   PetscCall(PetscOptionsString("-dm_forest_topology", "the topology of the forest's base mesh", "DMForestSetTopology", oldTopo, stringBuffer, sizeof(stringBuffer), &flg1));
1478   PetscCall(PetscOptionsViewer("-dm_forest_base_dm", "load the base DM from a viewer specification", "DMForestSetBaseDM", &viewer, &format, &flg2));
1479   PetscCall(PetscOptionsViewer("-dm_forest_coarse_forest", "load the coarse forest from a viewer specification", "DMForestSetCoarseForest", &viewer, &format, &flg3));
1480   PetscCall(PetscOptionsViewer("-dm_forest_fine_forest", "load the fine forest from a viewer specification", "DMForestSetFineForest", &viewer, &format, &flg4));
1481   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}");
1482   if (flg1) {
1483     PetscCall(DMForestSetTopology(dm, (DMForestTopology)stringBuffer));
1484     PetscCall(DMForestSetBaseDM(dm, NULL));
1485     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1486   }
1487   if (flg2) {
1488     DM base;
1489 
1490     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &base));
1491     PetscCall(PetscViewerPushFormat(viewer, format));
1492     PetscCall(DMLoad(base, viewer));
1493     PetscCall(PetscViewerDestroy(&viewer));
1494     PetscCall(DMForestSetBaseDM(dm, base));
1495     PetscCall(DMDestroy(&base));
1496     PetscCall(DMForestSetTopology(dm, NULL));
1497     PetscCall(DMForestSetAdaptivityForest(dm, NULL));
1498   }
1499   if (flg3) {
1500     DM coarse;
1501 
1502     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &coarse));
1503     PetscCall(PetscViewerPushFormat(viewer, format));
1504     PetscCall(DMLoad(coarse, viewer));
1505     PetscCall(PetscViewerDestroy(&viewer));
1506     PetscCall(DMForestSetAdaptivityForest(dm, coarse));
1507     PetscCall(DMDestroy(&coarse));
1508     PetscCall(DMForestSetTopology(dm, NULL));
1509     PetscCall(DMForestSetBaseDM(dm, NULL));
1510   }
1511   if (flg4) {
1512     DM fine;
1513 
1514     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &fine));
1515     PetscCall(PetscViewerPushFormat(viewer, format));
1516     PetscCall(DMLoad(fine, viewer));
1517     PetscCall(PetscViewerDestroy(&viewer));
1518     PetscCall(DMForestSetAdaptivityForest(dm, fine));
1519     PetscCall(DMDestroy(&fine));
1520     PetscCall(DMForestSetTopology(dm, NULL));
1521     PetscCall(DMForestSetBaseDM(dm, NULL));
1522   }
1523   PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
1524   PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_dimension", "set the dimension of points that define adjacency in the forest", "DMForestSetAdjacencyDimension", adjDim, &adjDim, &flg, 0));
1525   if (flg) {
1526     PetscCall(DMForestSetAdjacencyDimension(dm, adjDim));
1527   } else {
1528     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
1529     PetscCall(PetscOptionsBoundedInt("-dm_forest_adjacency_codimension", "set the codimension of points that define adjacency in the forest", "DMForestSetAdjacencyCodimension", adjCodim, &adjCodim, &flg, 1));
1530     if (flg) PetscCall(DMForestSetAdjacencyCodimension(dm, adjCodim));
1531   }
1532   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
1533   PetscCall(PetscOptionsBoundedInt("-dm_forest_partition_overlap", "set the degree of partition overlap", "DMForestSetPartitionOverlap", overlap, &overlap, &flg, 0));
1534   if (flg) PetscCall(DMForestSetPartitionOverlap(dm, overlap));
1535 #if 0
1536   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));
1537   if (flg) {
1538     PetscCall(DMForestSetMinimumRefinement(dm,minRefinement));
1539     PetscCall(DMForestSetInitialRefinement(dm,minRefinement));
1540   }
1541   PetscCall(PetscOptionsBoundedInt("-dm_refine_hierarchy","equivalent to -dm_forest_set_minimum_refinement 0 and -dm_forest_set_initial_refinement",NULL,initRefinement,&initRefinement,&flg,0));
1542   if (flg) {
1543     PetscCall(DMForestSetMinimumRefinement(dm,0));
1544     PetscCall(DMForestSetInitialRefinement(dm,initRefinement));
1545   }
1546 #endif
1547   PetscCall(DMForestGetMinimumRefinement(dm, &minRefinement));
1548   PetscCall(PetscOptionsBoundedInt("-dm_forest_minimum_refinement", "set the minimum level of refinement in the forest", "DMForestSetMinimumRefinement", minRefinement, &minRefinement, &flg, 0));
1549   if (flg) PetscCall(DMForestSetMinimumRefinement(dm, minRefinement));
1550   PetscCall(DMForestGetInitialRefinement(dm, &initRefinement));
1551   PetscCall(PetscOptionsBoundedInt("-dm_forest_initial_refinement", "set the initial level of refinement in the forest", "DMForestSetInitialRefinement", initRefinement, &initRefinement, &flg, 0));
1552   if (flg) PetscCall(DMForestSetInitialRefinement(dm, initRefinement));
1553   PetscCall(DMForestGetMaximumRefinement(dm, &maxRefinement));
1554   PetscCall(PetscOptionsBoundedInt("-dm_forest_maximum_refinement", "set the maximum level of refinement in the forest", "DMForestSetMaximumRefinement", maxRefinement, &maxRefinement, &flg, 0));
1555   if (flg) PetscCall(DMForestSetMaximumRefinement(dm, maxRefinement));
1556   PetscCall(DMForestGetAdaptivityStrategy(dm, &adaptStrategy));
1557   PetscCall(PetscOptionsString("-dm_forest_adaptivity_strategy", "the forest's adaptivity-flag resolution strategy", "DMForestSetAdaptivityStrategy", adaptStrategy, stringBuffer, sizeof(stringBuffer), &flg));
1558   if (flg) PetscCall(DMForestSetAdaptivityStrategy(dm, (DMForestAdaptivityStrategy)stringBuffer));
1559   PetscCall(DMForestGetGradeFactor(dm, &grade));
1560   PetscCall(PetscOptionsBoundedInt("-dm_forest_grade_factor", "grade factor between neighboring cells", "DMForestSetGradeFactor", grade, &grade, &flg, 0));
1561   if (flg) PetscCall(DMForestSetGradeFactor(dm, grade));
1562   PetscCall(DMForestGetCellWeightFactor(dm, &weightsFactor));
1563   PetscCall(PetscOptionsReal("-dm_forest_cell_weight_factor", "multiplying weight factor for cell refinement", "DMForestSetCellWeightFactor", weightsFactor, &weightsFactor, &flg));
1564   if (flg) PetscCall(DMForestSetCellWeightFactor(dm, weightsFactor));
1565   PetscOptionsHeadEnd();
1566   PetscFunctionReturn(PETSC_SUCCESS);
1567 }
1568 
1569 static PetscErrorCode DMCreateSubDM_Forest(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1570 {
1571   PetscFunctionBegin;
1572   if (subdm) PetscCall(DMClone(dm, subdm));
1573   PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm));
1574   PetscFunctionReturn(PETSC_SUCCESS);
1575 }
1576 
1577 static PetscErrorCode DMRefine_Forest(DM dm, MPI_Comm comm, DM *dmRefined)
1578 {
1579   DMLabel refine;
1580   DM      fineDM;
1581 
1582   PetscFunctionBegin;
1583   PetscCall(DMGetFineDM(dm, &fineDM));
1584   if (fineDM) {
1585     PetscCall(PetscObjectReference((PetscObject)fineDM));
1586     *dmRefined = fineDM;
1587     PetscFunctionReturn(PETSC_SUCCESS);
1588   }
1589   PetscCall(DMForestTemplate(dm, comm, dmRefined));
1590   PetscCall(DMGetLabel(dm, "refine", &refine));
1591   if (!refine) {
1592     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "refine", &refine));
1593     PetscCall(DMLabelSetDefaultValue(refine, DM_ADAPT_REFINE));
1594   } else PetscCall(PetscObjectReference((PetscObject)refine));
1595   PetscCall(DMForestSetAdaptivityLabel(*dmRefined, refine));
1596   PetscCall(DMLabelDestroy(&refine));
1597   PetscFunctionReturn(PETSC_SUCCESS);
1598 }
1599 
1600 static PetscErrorCode DMCoarsen_Forest(DM dm, MPI_Comm comm, DM *dmCoarsened)
1601 {
1602   DMLabel coarsen;
1603   DM      coarseDM;
1604 
1605   PetscFunctionBegin;
1606   if (comm != MPI_COMM_NULL) {
1607     PetscMPIInt mpiComparison;
1608     MPI_Comm    dmcomm = PetscObjectComm((PetscObject)dm);
1609 
1610     PetscCallMPI(MPI_Comm_compare(comm, dmcomm, &mpiComparison));
1611     PetscCheck(mpiComparison == MPI_IDENT || mpiComparison == MPI_CONGRUENT, dmcomm, PETSC_ERR_SUP, "No support for different communicators yet");
1612   }
1613   PetscCall(DMGetCoarseDM(dm, &coarseDM));
1614   if (coarseDM) {
1615     PetscCall(PetscObjectReference((PetscObject)coarseDM));
1616     *dmCoarsened = coarseDM;
1617     PetscFunctionReturn(PETSC_SUCCESS);
1618   }
1619   PetscCall(DMForestTemplate(dm, comm, dmCoarsened));
1620   PetscCall(DMForestSetAdaptivityPurpose(*dmCoarsened, DM_ADAPT_COARSEN));
1621   PetscCall(DMGetLabel(dm, "coarsen", &coarsen));
1622   if (!coarsen) {
1623     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
1624     PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
1625   } else PetscCall(PetscObjectReference((PetscObject)coarsen));
1626   PetscCall(DMForestSetAdaptivityLabel(*dmCoarsened, coarsen));
1627   PetscCall(DMLabelDestroy(&coarsen));
1628   PetscFunctionReturn(PETSC_SUCCESS);
1629 }
1630 
1631 PetscErrorCode DMAdaptLabel_Forest(DM dm, PETSC_UNUSED Vec metric, DMLabel label, PETSC_UNUSED DMLabel rgLabel, DM *adaptedDM)
1632 {
1633   PetscBool success;
1634 
1635   PetscFunctionBegin;
1636   PetscCall(DMForestTemplate(dm, PetscObjectComm((PetscObject)dm), adaptedDM));
1637   PetscCall(DMForestSetAdaptivityLabel(*adaptedDM, label));
1638   PetscCall(DMSetUp(*adaptedDM));
1639   PetscCall(DMForestGetAdaptivitySuccess(*adaptedDM, &success));
1640   if (!success) {
1641     PetscCall(DMDestroy(adaptedDM));
1642     *adaptedDM = NULL;
1643   }
1644   PetscFunctionReturn(PETSC_SUCCESS);
1645 }
1646 
1647 static PetscErrorCode DMInitialize_Forest(DM dm)
1648 {
1649   PetscFunctionBegin;
1650   PetscCall(PetscMemzero(dm->ops, sizeof(*(dm->ops))));
1651 
1652   dm->ops->clone          = DMClone_Forest;
1653   dm->ops->setfromoptions = DMSetFromOptions_Forest;
1654   dm->ops->destroy        = DMDestroy_Forest;
1655   dm->ops->createsubdm    = DMCreateSubDM_Forest;
1656   dm->ops->refine         = DMRefine_Forest;
1657   dm->ops->coarsen        = DMCoarsen_Forest;
1658   PetscFunctionReturn(PETSC_SUCCESS);
1659 }
1660 
1661 /*MC
1662 
1663      DMFOREST = "forest" - A DM object that encapsulates a hierarchically refined mesh.  Forests usually have a base `DM`
1664   (see `DMForestGetBaseDM()`), from which it is refined.  The refinement and partitioning of forests is considered
1665   immutable after `DMSetUp()` is called.  To adapt a mesh, one should call `DMForestTemplate()` to create a new mesh that
1666   will default to being identical to it, specify how that mesh should differ, and then calling `DMSetUp()` on the new
1667   mesh.
1668 
1669   To specify that a mesh should be refined or coarsened from the previous mesh, a label should be defined on the
1670   previous mesh whose values indicate which cells should be refined (`DM_ADAPT_REFINE`) or coarsened (`DM_ADAPT_COARSEN`)
1671   and how (subtypes are free to allow additional values for things like anisotropic refinement).  The label should be
1672   given to the *new* mesh with `DMForestSetAdaptivityLabel()`.
1673 
1674   Level: advanced
1675 
1676 .seealso: `DMType`, `DM`, `DMCreate()`, `DMSetType()`, `DMForestGetBaseDM()`, `DMForestSetBaseDM()`, `DMForestTemplate()`, `DMForestSetAdaptivityLabel()`
1677 M*/
1678 
1679 PETSC_EXTERN PetscErrorCode DMCreate_Forest(DM dm)
1680 {
1681   DM_Forest *forest;
1682 
1683   PetscFunctionBegin;
1684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1685   PetscCall(PetscNew(&forest));
1686   dm->dim                     = 0;
1687   dm->data                    = forest;
1688   forest->refct               = 1;
1689   forest->data                = NULL;
1690   forest->topology            = NULL;
1691   forest->adapt               = NULL;
1692   forest->base                = NULL;
1693   forest->adaptPurpose        = DM_ADAPT_DETERMINE;
1694   forest->adjDim              = PETSC_DEFAULT;
1695   forest->overlap             = PETSC_DEFAULT;
1696   forest->minRefinement       = PETSC_DEFAULT;
1697   forest->maxRefinement       = PETSC_DEFAULT;
1698   forest->initRefinement      = PETSC_DEFAULT;
1699   forest->cStart              = PETSC_DETERMINE;
1700   forest->cEnd                = PETSC_DETERMINE;
1701   forest->cellSF              = NULL;
1702   forest->adaptLabel          = NULL;
1703   forest->gradeFactor         = 2;
1704   forest->cellWeights         = NULL;
1705   forest->cellWeightsCopyMode = PETSC_USE_POINTER;
1706   forest->weightsFactor       = 1.;
1707   forest->weightCapacity      = 1.;
1708   PetscCall(DMForestSetAdaptivityStrategy(dm, DMFORESTADAPTALL));
1709   PetscCall(DMInitialize_Forest(dm));
1710   PetscFunctionReturn(PETSC_SUCCESS);
1711 }
1712