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