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