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