xref: /petsc/src/snes/utils/dm/dmadapt.c (revision 3a336bb1c5354aa6a7f04f397c2159a565cb027a)
1 #include <petscdmadaptor.h> /*I "petscdmadaptor.h" I*/
2 #include <petscdmplex.h>
3 #include <petscdmforest.h>
4 #include <petscds.h>
5 #include <petscblaslapack.h>
6 #include <petscsnes.h>
7 
8 #include <petsc/private/dmadaptorimpl.h>
9 #include <petsc/private/dmpleximpl.h>
10 #include <petsc/private/petscfeimpl.h>
11 
12 PetscClassId DMADAPTOR_CLASSID;
13 
14 PetscFunctionList DMAdaptorList              = NULL;
15 PetscBool         DMAdaptorRegisterAllCalled = PETSC_FALSE;
16 
17 /*@C
18   DMAdaptorRegister - Adds a new adaptor component implementation
19 
20   Not Collective
21 
22   Input Parameters:
23 + name        - The name of a new user-defined creation routine
24 - create_func - The creation routine
25 
26   Example Usage:
27 .vb
28   DMAdaptorRegister("my_adaptor", MyAdaptorCreate);
29 .ve
30 
31   Then, your adaptor type can be chosen with the procedural interface via
32 .vb
33   DMAdaptorCreate(MPI_Comm, DMAdaptor *);
34   DMAdaptorSetType(DMAdaptor, "my_adaptor");
35 .ve
36   or at runtime via the option
37 .vb
38   -adaptor_type my_adaptor
39 .ve
40 
41   Level: advanced
42 
43   Note:
44   `DMAdaptorRegister()` may be called multiple times to add several user-defined adaptors
45 
46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorRegisterAll()`, `DMAdaptorRegisterDestroy()`
47 @*/
48 PetscErrorCode DMAdaptorRegister(const char name[], PetscErrorCode (*create_func)(DMAdaptor))
49 {
50   PetscFunctionBegin;
51   PetscCall(DMInitializePackage());
52   PetscCall(PetscFunctionListAdd(&DMAdaptorList, name, create_func));
53   PetscFunctionReturn(PETSC_SUCCESS);
54 }
55 
56 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor);
57 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor);
58 
59 /*@C
60   DMAdaptorRegisterAll - Registers all of the adaptor components in the `DM` package.
61 
62   Not Collective
63 
64   Level: advanced
65 
66 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptorType`, `DMRegisterAll()`, `DMAdaptorRegisterDestroy()`
67 @*/
68 PetscErrorCode DMAdaptorRegisterAll(void)
69 {
70   PetscFunctionBegin;
71   if (DMAdaptorRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
72   DMAdaptorRegisterAllCalled = PETSC_TRUE;
73 
74   PetscCall(DMAdaptorRegister(DMADAPTORGRADIENT, DMAdaptorCreate_Gradient));
75   PetscCall(DMAdaptorRegister(DMADAPTORFLUX, DMAdaptorCreate_Flux));
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 /*@C
80   DMAdaptorRegisterDestroy - This function destroys the registered `DMAdaptorType`. It is called from `PetscFinalize()`.
81 
82   Not collective
83 
84   Level: developer
85 
86 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMAdaptorType`, `PetscInitialize()`
87 @*/
88 PetscErrorCode DMAdaptorRegisterDestroy(void)
89 {
90   PetscFunctionBegin;
91   PetscCall(PetscFunctionListDestroy(&DMAdaptorList));
92   DMAdaptorRegisterAllCalled = PETSC_FALSE;
93   PetscFunctionReturn(PETSC_SUCCESS);
94 }
95 
96 /*@
97   DMAdaptorCreate - Create a `DMAdaptor` object. Its purpose is to construct a adaptation `DMLabel` or metric `Vec` that can be used to modify the `DM`.
98 
99   Collective
100 
101   Input Parameter:
102 . comm - The communicator for the `DMAdaptor` object
103 
104   Output Parameter:
105 . adaptor - The `DMAdaptor` object
106 
107   Level: beginner
108 
109 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorDestroy()`, `DMAdaptorAdapt()`, `PetscConvEst`, `PetscConvEstCreate()`
110 @*/
111 PetscErrorCode DMAdaptorCreate(MPI_Comm comm, DMAdaptor *adaptor)
112 {
113   VecTaggerBox refineBox, coarsenBox;
114 
115   PetscFunctionBegin;
116   PetscAssertPointer(adaptor, 2);
117   PetscCall(PetscSysInitializePackage());
118 
119   PetscCall(PetscHeaderCreate(*adaptor, DMADAPTOR_CLASSID, "DMAdaptor", "DM Adaptor", "DMAdaptor", comm, DMAdaptorDestroy, DMAdaptorView));
120   (*adaptor)->monitor          = PETSC_FALSE;
121   (*adaptor)->adaptCriterion   = DM_ADAPTATION_NONE;
122   (*adaptor)->numSeq           = 1;
123   (*adaptor)->Nadapt           = -1;
124   (*adaptor)->refinementFactor = 2.0;
125   refineBox.min = refineBox.max = PETSC_MAX_REAL;
126   PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->refineTag));
127   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->refineTag, "refine_"));
128   PetscCall(VecTaggerSetType((*adaptor)->refineTag, VECTAGGERABSOLUTE));
129   PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->refineTag, &refineBox));
130   coarsenBox.min = coarsenBox.max = PETSC_MAX_REAL;
131   PetscCall(VecTaggerCreate(PetscObjectComm((PetscObject)*adaptor), &(*adaptor)->coarsenTag));
132   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(*adaptor)->coarsenTag, "coarsen_"));
133   PetscCall(VecTaggerSetType((*adaptor)->coarsenTag, VECTAGGERABSOLUTE));
134   PetscCall(VecTaggerAbsoluteSetBox((*adaptor)->coarsenTag, &coarsenBox));
135   PetscFunctionReturn(PETSC_SUCCESS);
136 }
137 
138 /*@
139   DMAdaptorDestroy - Destroys a `DMAdaptor` object
140 
141   Collective
142 
143   Input Parameter:
144 . adaptor - The `DMAdaptor` object
145 
146   Level: beginner
147 
148 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
149 @*/
150 PetscErrorCode DMAdaptorDestroy(DMAdaptor *adaptor)
151 {
152   PetscFunctionBegin;
153   if (!*adaptor) PetscFunctionReturn(PETSC_SUCCESS);
154   PetscValidHeaderSpecific(*adaptor, DMADAPTOR_CLASSID, 1);
155   if (--((PetscObject)*adaptor)->refct > 0) {
156     *adaptor = NULL;
157     PetscFunctionReturn(PETSC_SUCCESS);
158   }
159   PetscCall(VecTaggerDestroy(&(*adaptor)->refineTag));
160   PetscCall(VecTaggerDestroy(&(*adaptor)->coarsenTag));
161   PetscCall(PetscFree2((*adaptor)->exactSol, (*adaptor)->exactCtx));
162   PetscCall(PetscHeaderDestroy(adaptor));
163   PetscFunctionReturn(PETSC_SUCCESS);
164 }
165 
166 /*@
167   DMAdaptorSetType - Sets the particular implementation for a adaptor.
168 
169   Collective
170 
171   Input Parameters:
172 + adaptor - The `DMAdaptor`
173 - method  - The name of the adaptor type
174 
175   Options Database Key:
176 . -adaptor_type <type> - Sets the adaptor type; see `DMAdaptorType`
177 
178   Level: intermediate
179 
180 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorGetType()`, `DMAdaptorCreate()`
181 @*/
182 PetscErrorCode DMAdaptorSetType(DMAdaptor adaptor, DMAdaptorType method)
183 {
184   PetscErrorCode (*r)(DMAdaptor);
185   PetscBool match;
186 
187   PetscFunctionBegin;
188   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
189   PetscCall(PetscObjectTypeCompare((PetscObject)adaptor, method, &match));
190   if (match) PetscFunctionReturn(PETSC_SUCCESS);
191 
192   PetscCall(DMAdaptorRegisterAll());
193   PetscCall(PetscFunctionListFind(DMAdaptorList, method, &r));
194   PetscCheck(r, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMAdaptor type: %s", method);
195 
196   PetscTryTypeMethod(adaptor, destroy);
197   PetscCall(PetscMemzero(adaptor->ops, sizeof(*adaptor->ops)));
198   PetscCall(PetscObjectChangeTypeName((PetscObject)adaptor, method));
199   PetscCall((*r)(adaptor));
200   PetscFunctionReturn(PETSC_SUCCESS);
201 }
202 
203 /*@
204   DMAdaptorGetType - Gets the type name (as a string) from the adaptor.
205 
206   Not Collective
207 
208   Input Parameter:
209 . adaptor - The `DMAdaptor`
210 
211   Output Parameter:
212 . type - The `DMAdaptorType` name
213 
214   Level: intermediate
215 
216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMAdaptor`, `DMAdaptorType`, `DMAdaptorSetType()`, `DMAdaptorCreate()`
217 @*/
218 PetscErrorCode DMAdaptorGetType(DMAdaptor adaptor, DMAdaptorType *type)
219 {
220   PetscFunctionBegin;
221   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
222   PetscAssertPointer(type, 2);
223   PetscCall(DMAdaptorRegisterAll());
224   *type = ((PetscObject)adaptor)->type_name;
225   PetscFunctionReturn(PETSC_SUCCESS);
226 }
227 
228 /*@
229   DMAdaptorSetFromOptions - Sets properties of a `DMAdaptor` object from values in the options database
230 
231   Collective
232 
233   Input Parameter:
234 . adaptor - The `DMAdaptor` object
235 
236   Options Database Keys:
237 + -adaptor_monitor <bool>              - Monitor the adaptation process
238 . -adaptor_sequence_num <num>          - Number of adaptations to generate an optimal grid
239 . -adaptor_target_num <num>            - Set the target number of vertices N_adapt, -1 for automatic determination
240 . -adaptor_refinement_factor <r>       - Set r such that N_adapt = r^dim N_orig
241 - -adaptor_mixed_setup_function <func> - Set the fnction func that sets up the mixed problem
242 
243   Level: beginner
244 
245 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
246 @*/
247 PetscErrorCode DMAdaptorSetFromOptions(DMAdaptor adaptor)
248 {
249   char        typeName[PETSC_MAX_PATH_LEN];
250   const char *defName = DMADAPTORGRADIENT;
251   char        funcname[PETSC_MAX_PATH_LEN];
252   PetscBool   flg;
253 
254   PetscFunctionBegin;
255   PetscObjectOptionsBegin((PetscObject)adaptor);
256   PetscCall(PetscOptionsFList("-adaptor_type", "DMAdaptor", "DMAdaptorSetType", DMAdaptorList, defName, typeName, 1024, &flg));
257   if (flg) PetscCall(DMAdaptorSetType(adaptor, typeName));
258   else if (!((PetscObject)adaptor)->type_name) PetscCall(DMAdaptorSetType(adaptor, defName));
259   PetscCall(PetscOptionsBool("-adaptor_monitor", "Monitor the adaptation process", "DMAdaptorMonitor", adaptor->monitor, &adaptor->monitor, NULL));
260   PetscCall(PetscOptionsInt("-adaptor_sequence_num", "Number of adaptations to generate an optimal grid", "DMAdaptorSetSequenceLength", adaptor->numSeq, &adaptor->numSeq, NULL));
261   PetscCall(PetscOptionsInt("-adaptor_target_num", "Set the target number of vertices N_adapt, -1 for automatic determination", "DMAdaptor", adaptor->Nadapt, &adaptor->Nadapt, NULL));
262   PetscCall(PetscOptionsReal("-adaptor_refinement_factor", "Set r such that N_adapt = r^dim N_orig", "DMAdaptor", adaptor->refinementFactor, &adaptor->refinementFactor, NULL));
263   PetscCall(PetscOptionsString("-adaptor_mixed_setup_function", "Function to setup the mixed problem", "DMAdaptorSetMixedSetupFunction", funcname, funcname, sizeof(funcname), &flg));
264   if (flg) {
265     PetscErrorCode (*setupFunc)(DMAdaptor, DM);
266 
267     PetscCall(PetscDLSym(NULL, funcname, (void **)&setupFunc));
268     PetscCheck(setupFunc, PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Could not locate function %s", funcname);
269     PetscCall(DMAdaptorSetMixedSetupFunction(adaptor, setupFunc));
270   }
271   PetscOptionsEnd();
272   PetscCall(VecTaggerSetFromOptions(adaptor->refineTag));
273   PetscCall(VecTaggerSetFromOptions(adaptor->coarsenTag));
274   PetscFunctionReturn(PETSC_SUCCESS);
275 }
276 
277 /*@
278   DMAdaptorView - Views a `DMAdaptor` object
279 
280   Collective
281 
282   Input Parameters:
283 + adaptor - The `DMAdaptor` object
284 - viewer  - The `PetscViewer` object
285 
286   Level: beginner
287 
288 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
289 @*/
290 PetscErrorCode DMAdaptorView(DMAdaptor adaptor, PetscViewer viewer)
291 {
292   PetscFunctionBegin;
293   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)adaptor, viewer));
294   PetscCall(PetscViewerASCIIPrintf(viewer, "DM Adaptor\n"));
295   PetscCall(PetscViewerASCIIPrintf(viewer, "  sequence length: %" PetscInt_FMT "\n", adaptor->numSeq));
296   PetscCall(VecTaggerView(adaptor->refineTag, viewer));
297   PetscCall(VecTaggerView(adaptor->coarsenTag, viewer));
298   PetscFunctionReturn(PETSC_SUCCESS);
299 }
300 
301 /*@
302   DMAdaptorGetSolver - Gets the solver used to produce discrete solutions
303 
304   Not Collective
305 
306   Input Parameter:
307 . adaptor - The `DMAdaptor` object
308 
309   Output Parameter:
310 . snes - The solver
311 
312   Level: intermediate
313 
314 .seealso: [](ch_dmbase), `DM`, `DMAdaptor`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
315 @*/
316 PetscErrorCode DMAdaptorGetSolver(DMAdaptor adaptor, SNES *snes)
317 {
318   PetscFunctionBegin;
319   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
320   PetscAssertPointer(snes, 2);
321   *snes = adaptor->snes;
322   PetscFunctionReturn(PETSC_SUCCESS);
323 }
324 
325 /*@
326   DMAdaptorSetSolver - Sets the solver used to produce discrete solutions
327 
328   Not Collective
329 
330   Input Parameters:
331 + adaptor - The `DMAdaptor` object
332 - snes    - The solver, this MUST have an attached `DM`/`PetscDS`, so that the exact solution can be computed
333 
334   Level: intermediate
335 
336 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorGetSolver()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
337 @*/
338 PetscErrorCode DMAdaptorSetSolver(DMAdaptor adaptor, SNES snes)
339 {
340   PetscFunctionBegin;
341   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
342   PetscValidHeaderSpecific(snes, SNES_CLASSID, 2);
343   adaptor->snes = snes;
344   PetscCall(SNESGetDM(adaptor->snes, &adaptor->idm));
345   PetscFunctionReturn(PETSC_SUCCESS);
346 }
347 
348 /*@
349   DMAdaptorGetSequenceLength - Gets the number of sequential adaptations used by an adapter
350 
351   Not Collective
352 
353   Input Parameter:
354 . adaptor - The `DMAdaptor` object
355 
356   Output Parameter:
357 . num - The number of adaptations
358 
359   Level: intermediate
360 
361 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorSetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
362 @*/
363 PetscErrorCode DMAdaptorGetSequenceLength(DMAdaptor adaptor, PetscInt *num)
364 {
365   PetscFunctionBegin;
366   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
367   PetscAssertPointer(num, 2);
368   *num = adaptor->numSeq;
369   PetscFunctionReturn(PETSC_SUCCESS);
370 }
371 
372 /*@
373   DMAdaptorSetSequenceLength - Sets the number of sequential adaptations
374 
375   Not Collective
376 
377   Input Parameters:
378 + adaptor - The `DMAdaptor` object
379 - num     - The number of adaptations
380 
381   Level: intermediate
382 
383 .seealso: [](ch_dmbase), `DMAdaptorGetSequenceLength()`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
384 @*/
385 PetscErrorCode DMAdaptorSetSequenceLength(DMAdaptor adaptor, PetscInt num)
386 {
387   PetscFunctionBegin;
388   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
389   adaptor->numSeq = num;
390   PetscFunctionReturn(PETSC_SUCCESS);
391 }
392 
393 static PetscErrorCode DMAdaptorTransferSolution_Exact_Private(DMAdaptor adaptor, DM dm, Vec u, DM adm, Vec au, void *ctx)
394 {
395   PetscFunctionBeginUser;
396   PetscCall(DMProjectFunction(adm, 0.0, adaptor->exactSol, adaptor->exactCtx, INSERT_ALL_VALUES, au));
397   PetscFunctionReturn(PETSC_SUCCESS);
398 }
399 
400 /*@
401   DMAdaptorSetUp - After the solver is specified, creates data structures for controlling adaptivity
402 
403   Collective
404 
405   Input Parameter:
406 . adaptor - The `DMAdaptor` object
407 
408   Level: beginner
409 
410 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptorCreate()`, `DMAdaptorAdapt()`
411 @*/
412 PetscErrorCode DMAdaptorSetUp(DMAdaptor adaptor)
413 {
414   PetscDS  prob;
415   PetscInt Nf, f;
416 
417   PetscFunctionBegin;
418   PetscCall(DMGetDS(adaptor->idm, &prob));
419   PetscCall(VecTaggerSetUp(adaptor->refineTag));
420   PetscCall(VecTaggerSetUp(adaptor->coarsenTag));
421   PetscCall(PetscDSGetNumFields(prob, &Nf));
422   PetscCall(PetscMalloc2(Nf, &adaptor->exactSol, Nf, &adaptor->exactCtx));
423   for (f = 0; f < Nf; ++f) {
424     PetscCall(PetscDSGetExactSolution(prob, f, &adaptor->exactSol[f], &adaptor->exactCtx[f]));
425     /* TODO Have a flag that forces projection rather than using the exact solution */
426     if (adaptor->exactSol[0]) PetscCall(DMAdaptorSetTransferFunction(adaptor, DMAdaptorTransferSolution_Exact_Private));
427   }
428   PetscTryTypeMethod(adaptor, setup);
429   PetscFunctionReturn(PETSC_SUCCESS);
430 }
431 
432 PetscErrorCode DMAdaptorGetTransferFunction(DMAdaptor adaptor, PetscErrorCode (**tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *))
433 {
434   PetscFunctionBegin;
435   *tfunc = adaptor->ops->transfersolution;
436   PetscFunctionReturn(PETSC_SUCCESS);
437 }
438 
439 PetscErrorCode DMAdaptorSetTransferFunction(DMAdaptor adaptor, PetscErrorCode (*tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *))
440 {
441   PetscFunctionBegin;
442   adaptor->ops->transfersolution = tfunc;
443   PetscFunctionReturn(PETSC_SUCCESS);
444 }
445 
446 static PetscErrorCode DMAdaptorPreAdapt(DMAdaptor adaptor, Vec locX)
447 {
448   DM           plex;
449   PetscDS      prob;
450   PetscObject  obj;
451   PetscClassId id;
452   PetscBool    isForest;
453 
454   PetscFunctionBegin;
455   PetscCall(DMConvert(adaptor->idm, DMPLEX, &plex));
456   PetscCall(DMGetDS(adaptor->idm, &prob));
457   PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
458   PetscCall(PetscObjectGetClassId(obj, &id));
459   PetscCall(DMIsForest(adaptor->idm, &isForest));
460   if (adaptor->adaptCriterion == DM_ADAPTATION_NONE) {
461     if (isForest) {
462       adaptor->adaptCriterion = DM_ADAPTATION_LABEL;
463     }
464 #if defined(PETSC_HAVE_PRAGMATIC)
465     else {
466       adaptor->adaptCriterion = DM_ADAPTATION_METRIC;
467     }
468 #elif defined(PETSC_HAVE_MMG)
469     else {
470       adaptor->adaptCriterion = DM_ADAPTATION_METRIC;
471     }
472 #elif defined(PETSC_HAVE_PARMMG)
473     else {
474       adaptor->adaptCriterion = DM_ADAPTATION_METRIC;
475     }
476 #else
477     else {
478       adaptor->adaptCriterion = DM_ADAPTATION_LABEL;
479     }
480 #endif
481   }
482   if (id == PETSCFV_CLASSID) {
483     adaptor->femType = PETSC_FALSE;
484   } else {
485     adaptor->femType = PETSC_TRUE;
486   }
487   if (adaptor->femType) {
488     /* Compute local solution bc */
489     PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL));
490   } else {
491     PetscFV      fvm = (PetscFV)obj;
492     PetscLimiter noneLimiter;
493     Vec          grad;
494 
495     PetscCall(PetscFVGetComputeGradients(fvm, &adaptor->computeGradient));
496     PetscCall(PetscFVSetComputeGradients(fvm, PETSC_TRUE));
497     /* Use no limiting when reconstructing gradients for adaptivity */
498     PetscCall(PetscFVGetLimiter(fvm, &adaptor->limiter));
499     PetscCall(PetscObjectReference((PetscObject)adaptor->limiter));
500     PetscCall(PetscLimiterCreate(PetscObjectComm((PetscObject)fvm), &noneLimiter));
501     PetscCall(PetscLimiterSetType(noneLimiter, PETSCLIMITERNONE));
502     PetscCall(PetscFVSetLimiter(fvm, noneLimiter));
503     /* Get FVM data */
504     PetscCall(DMPlexGetDataFVM(plex, fvm, &adaptor->cellGeom, &adaptor->faceGeom, &adaptor->gradDM));
505     PetscCall(VecGetDM(adaptor->cellGeom, &adaptor->cellDM));
506     PetscCall(VecGetArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray));
507     /* Compute local solution bc */
508     PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL));
509     /* Compute gradients */
510     PetscCall(DMCreateGlobalVector(adaptor->gradDM, &grad));
511     PetscCall(DMPlexReconstructGradientsFVM(plex, locX, grad));
512     PetscCall(DMGetLocalVector(adaptor->gradDM, &adaptor->cellGrad));
513     PetscCall(DMGlobalToLocalBegin(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad));
514     PetscCall(DMGlobalToLocalEnd(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad));
515     PetscCall(VecDestroy(&grad));
516     PetscCall(VecGetArrayRead(adaptor->cellGrad, &adaptor->cellGradArray));
517   }
518   PetscCall(DMDestroy(&plex));
519   PetscFunctionReturn(PETSC_SUCCESS);
520 }
521 
522 static PetscErrorCode DMAdaptorTransferSolution(DMAdaptor adaptor, DM dm, Vec x, DM adm, Vec ax)
523 {
524   PetscReal time = 0.0;
525   Mat       interp;
526   void     *ctx;
527 
528   PetscFunctionBegin;
529   PetscCall(DMGetApplicationContext(dm, &ctx));
530   if (adaptor->ops->transfersolution) PetscUseTypeMethod(adaptor, transfersolution, dm, x, adm, ax, ctx);
531   else {
532     switch (adaptor->adaptCriterion) {
533     case DM_ADAPTATION_LABEL:
534       PetscCall(DMForestTransferVec(dm, x, adm, ax, PETSC_TRUE, time));
535       break;
536     case DM_ADAPTATION_REFINE:
537     case DM_ADAPTATION_METRIC:
538       PetscCall(DMCreateInterpolation(dm, adm, &interp, NULL));
539       PetscCall(MatInterpolate(interp, x, ax));
540       PetscCall(DMInterpolate(dm, interp, adm));
541       PetscCall(MatDestroy(&interp));
542       break;
543     default:
544       SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_SUP, "No built-in projection for this adaptation criterion: %d", adaptor->adaptCriterion);
545     }
546   }
547   PetscFunctionReturn(PETSC_SUCCESS);
548 }
549 
550 static PetscErrorCode DMAdaptorPostAdapt(DMAdaptor adaptor)
551 {
552   PetscDS      prob;
553   PetscObject  obj;
554   PetscClassId id;
555 
556   PetscFunctionBegin;
557   PetscCall(DMGetDS(adaptor->idm, &prob));
558   PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
559   PetscCall(PetscObjectGetClassId(obj, &id));
560   if (id == PETSCFV_CLASSID) {
561     PetscFV fvm = (PetscFV)obj;
562 
563     PetscCall(PetscFVSetComputeGradients(fvm, adaptor->computeGradient));
564     /* Restore original limiter */
565     PetscCall(PetscFVSetLimiter(fvm, adaptor->limiter));
566 
567     PetscCall(VecRestoreArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray));
568     PetscCall(VecRestoreArrayRead(adaptor->cellGrad, &adaptor->cellGradArray));
569     PetscCall(DMRestoreLocalVector(adaptor->gradDM, &adaptor->cellGrad));
570   }
571   PetscFunctionReturn(PETSC_SUCCESS);
572 }
573 
574 /*
575   DMAdaptorComputeCellErrorIndicator_Gradient - Use the integrated gradient as an error indicator in the `DMAdaptor`
576 
577   Input Parameters:
578 + adaptor  - The `DMAdaptor` object
579 . dim      - The topological dimension
580 . cell     - The cell
581 . field    - The field integrated over the cell
582 . gradient - The gradient integrated over the cell
583 . cg       - A `PetscFVCellGeom` struct
584 - ctx      - A user context
585 
586   Output Parameter:
587 . errInd   - The error indicator
588 
589   Developer Note:
590   Some of the input arguments are absurdly specialized to special situations, it is not clear this is a good general API
591 
592 .seealso: [](ch_dmbase), `DMAdaptor`
593 */
594 static PetscErrorCode DMAdaptorComputeCellErrorIndicator_Gradient(DMAdaptor adaptor, PetscInt dim, PetscInt Nc, const PetscScalar *field, const PetscScalar *gradient, const PetscFVCellGeom *cg, PetscReal *errInd, void *ctx)
595 {
596   PetscReal err = 0.;
597   PetscInt  c, d;
598 
599   PetscFunctionBeginHot;
600   for (c = 0; c < Nc; c++) {
601     for (d = 0; d < dim; ++d) err += PetscSqr(PetscRealPart(gradient[c * dim + d]));
602   }
603   *errInd = cg->volume * err;
604   PetscFunctionReturn(PETSC_SUCCESS);
605 }
606 
607 static PetscErrorCode DMAdaptorComputeErrorIndicator_Gradient(DMAdaptor adaptor, Vec locX, Vec errVec)
608 {
609   DM              dm, plex, edm, eplex;
610   PetscDS         ds;
611   PetscObject     obj;
612   PetscClassId    id;
613   void           *ctx;
614   PetscQuadrature quad;
615   PetscScalar    *earray;
616   PetscReal       minMaxInd[2] = {PETSC_MAX_REAL, PETSC_MIN_REAL}, minMaxIndGlobal[2];
617   PetscInt        dim, cdim, cStart, cEnd, Nf, Nc;
618 
619   PetscFunctionBegin;
620   PetscCall(VecGetDM(locX, &dm));
621   PetscCall(DMConvert(dm, DMPLEX, &plex));
622   PetscCall(VecGetDM(errVec, &edm));
623   PetscCall(DMConvert(edm, DMPLEX, &eplex));
624   PetscCall(DMGetDimension(plex, &dim));
625   PetscCall(DMGetCoordinateDim(plex, &cdim));
626   PetscCall(DMGetApplicationContext(plex, &ctx));
627   PetscCall(DMGetDS(plex, &ds));
628   PetscCall(PetscDSGetNumFields(ds, &Nf));
629   PetscCall(PetscDSGetDiscretization(ds, 0, &obj));
630   PetscCall(PetscObjectGetClassId(obj, &id));
631 
632   PetscCall(VecGetArray(errVec, &earray));
633   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd));
634   for (PetscInt cell = cStart; cell < cEnd; ++cell) {
635     PetscScalar *eval;
636     PetscReal    errInd = 0.;
637 
638     if (id == PETSCFV_CLASSID) {
639       PetscFV            fv = (PetscFV)obj;
640       const PetscScalar *pointSols;
641       const PetscScalar *pointSol;
642       const PetscScalar *pointGrad;
643       PetscFVCellGeom   *cg;
644 
645       PetscCall(PetscFVGetNumComponents(fv, &Nc));
646       PetscCall(VecGetArrayRead(locX, &pointSols));
647       PetscCall(DMPlexPointLocalRead(plex, cell, pointSols, (void *)&pointSol));
648       PetscCall(DMPlexPointLocalRead(adaptor->gradDM, cell, adaptor->cellGradArray, (void *)&pointGrad));
649       PetscCall(DMPlexPointLocalRead(adaptor->cellDM, cell, adaptor->cellGeomArray, &cg));
650       PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, pointSol, pointGrad, cg, &errInd, ctx);
651       PetscCall(VecRestoreArrayRead(locX, &pointSols));
652     } else {
653       PetscFE          fe = (PetscFE)obj;
654       PetscScalar     *x  = NULL, *field, *gradient, *interpolant, *interpolantGrad;
655       PetscFVCellGeom  cg;
656       PetscFEGeom      fegeom;
657       const PetscReal *quadWeights;
658       PetscReal       *coords;
659       PetscInt         Nb, Nq, qNc;
660 
661       fegeom.dim      = dim;
662       fegeom.dimEmbed = cdim;
663       PetscCall(PetscFEGetNumComponents(fe, &Nc));
664       PetscCall(PetscFEGetQuadrature(fe, &quad));
665       PetscCall(PetscFEGetDimension(fe, &Nb));
666       PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
667       PetscCall(PetscCalloc6(Nc, &field, cdim * Nc, &gradient, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ));
668       PetscCall(PetscMalloc2(Nc, &interpolant, cdim * Nc, &interpolantGrad));
669       PetscCall(DMPlexComputeCellGeometryFEM(plex, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
670       PetscCall(DMPlexComputeCellGeometryFVM(plex, cell, &cg.volume, NULL, NULL));
671       PetscCall(PetscArrayzero(gradient, cdim * Nc));
672       PetscCall(DMPlexVecGetClosure(plex, NULL, locX, cell, NULL, &x));
673       for (PetscInt f = 0; f < Nf; ++f) {
674         PetscInt qc = 0;
675 
676         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
677         PetscCall(PetscArrayzero(interpolant, Nc));
678         PetscCall(PetscArrayzero(interpolantGrad, cdim * Nc));
679         for (PetscInt q = 0; q < Nq; ++q) {
680           PetscCall(PetscFEInterpolateFieldAndGradient_Static((PetscFE)obj, 1, x, &fegeom, q, interpolant, interpolantGrad));
681           for (PetscInt fc = 0; fc < Nc; ++fc) {
682             const PetscReal wt = quadWeights[q * qNc + qc + fc];
683 
684             field[fc] += interpolant[fc] * wt * fegeom.detJ[q];
685             for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] += interpolantGrad[fc * dim + d] * wt * fegeom.detJ[q];
686           }
687         }
688         qc += Nc;
689       }
690       PetscCall(PetscFree2(interpolant, interpolantGrad));
691       PetscCall(DMPlexVecRestoreClosure(plex, NULL, locX, cell, NULL, &x));
692       for (PetscInt fc = 0; fc < Nc; ++fc) {
693         field[fc] /= cg.volume;
694         for (PetscInt d = 0; d < cdim; ++d) gradient[fc * cdim + d] /= cg.volume;
695       }
696       PetscUseTypeMethod(adaptor, computecellerrorindicator, dim, Nc, field, gradient, &cg, &errInd, ctx);
697       PetscCall(PetscFree6(field, gradient, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
698     }
699     PetscCall(DMPlexPointGlobalRef(eplex, cell, earray, (void *)&eval));
700     eval[0]      = errInd;
701     minMaxInd[0] = PetscMin(minMaxInd[0], errInd);
702     minMaxInd[1] = PetscMax(minMaxInd[1], errInd);
703   }
704   PetscCall(VecRestoreArray(errVec, &earray));
705   PetscCall(DMDestroy(&plex));
706   PetscCall(DMDestroy(&eplex));
707   PetscCall(PetscGlobalMinMaxReal(PetscObjectComm((PetscObject)adaptor), minMaxInd, minMaxIndGlobal));
708   PetscCall(PetscInfo(adaptor, "DMAdaptor: error indicator range (%g, %g)\n", (double)minMaxIndGlobal[0], (double)minMaxIndGlobal[1]));
709   PetscFunctionReturn(PETSC_SUCCESS);
710 }
711 
712 static PetscErrorCode DMAdaptorComputeErrorIndicator_Flux(DMAdaptor adaptor, Vec lu, Vec errVec)
713 {
714   DM    dm, mdm;
715   SNES  msnes;
716   Vec   mu, lmu;
717   void *ctx;
718 
719   PetscFunctionBegin;
720   PetscCall(VecGetDM(lu, &dm));
721 
722   // Set up and solve mixed problem
723   PetscCall(DMClone(dm, &mdm));
724   PetscCall(SNESCreate(PetscObjectComm((PetscObject)mdm), &msnes));
725   PetscCall(SNESSetDM(msnes, mdm));
726   PetscCall(SNESAppendOptionsPrefix(msnes, "mixed_"));
727 
728   PetscTryTypeMethod(adaptor, mixedsetup, mdm);
729   PetscCall(DMGetApplicationContext(dm, &ctx));
730   PetscCall(DMPlexSetSNESLocalFEM(mdm, PETSC_FALSE, ctx));
731   PetscCall(SNESSetFromOptions(msnes));
732 
733   PetscCall(DMCreateGlobalVector(mdm, &mu));
734   PetscCall(PetscObjectSetName((PetscObject)mu, "Mixed Solution"));
735   PetscCall(VecSet(mu, 0.0));
736   PetscCall(SNESSolve(msnes, NULL, mu));
737   PetscCall(VecViewFromOptions(mu, (PetscObject)adaptor, "-adapt_mixed_sol_vec_view"));
738 
739   PetscCall(DMGetLocalVector(mdm, &lmu));
740   PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu));
741   PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL));
742   PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, 0, lmu, 0, errVec));
743   PetscCall(DMRestoreLocalVector(mdm, &lmu));
744   PetscCall(VecDestroy(&mu));
745   PetscCall(SNESDestroy(&msnes));
746   PetscCall(DMDestroy(&mdm));
747   PetscFunctionReturn(PETSC_SUCCESS);
748 }
749 
750 static void identityFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
751 {
752   PetscInt i, j;
753 
754   for (i = 0; i < dim; ++i) {
755     for (j = 0; j < dim; ++j) f[i + dim * j] = u[i + dim * j];
756   }
757 }
758 
759 static PetscErrorCode DMAdaptorAdapt_Sequence_Private(DMAdaptor adaptor, Vec inx, PetscBool doSolve, DM *adm, Vec *ax)
760 {
761   PetscDS  ds;
762   void    *ctx;
763   MPI_Comm comm;
764   PetscInt numAdapt = adaptor->numSeq, adaptIter;
765   PetscInt dim, coordDim, Nf;
766 
767   PetscFunctionBegin;
768   PetscCall(DMViewFromOptions(adaptor->idm, NULL, "-dm_adapt_pre_view"));
769   PetscCall(VecViewFromOptions(inx, NULL, "-sol_adapt_pre_view"));
770   PetscCall(PetscObjectGetComm((PetscObject)adaptor, &comm));
771   PetscCall(DMGetDimension(adaptor->idm, &dim));
772   PetscCall(DMGetCoordinateDim(adaptor->idm, &coordDim));
773   PetscCall(DMGetApplicationContext(adaptor->idm, &ctx));
774   PetscCall(DMGetDS(adaptor->idm, &ds));
775   PetscCall(PetscDSGetNumFields(ds, &Nf));
776   PetscCheck(Nf != 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot refine with no fields present!");
777 
778   /* Adapt until nothing changes */
779   /* Adapt for a specified number of iterates */
780   for (adaptIter = 0; adaptIter < numAdapt - 1; ++adaptIter) PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_(comm)));
781   for (adaptIter = 0; adaptIter < numAdapt; ++adaptIter) {
782     PetscBool adapted = PETSC_FALSE;
783     DM        dm      = adaptIter ? *adm : adaptor->idm, odm;
784     Vec       x       = adaptIter ? *ax : inx, locX, ox;
785 
786     PetscCall(DMGetLocalVector(dm, &locX));
787     PetscCall(DMAdaptorPreAdapt(adaptor, locX));
788     if (doSolve) {
789       SNES snes;
790 
791       PetscCall(DMAdaptorGetSolver(adaptor, &snes));
792       PetscCall(SNESSolve(snes, NULL, adaptIter ? *ax : x));
793     }
794     PetscCall(DMGlobalToLocalBegin(dm, adaptIter ? *ax : x, INSERT_VALUES, locX));
795     PetscCall(DMGlobalToLocalEnd(dm, adaptIter ? *ax : x, INSERT_VALUES, locX));
796     PetscCall(VecViewFromOptions(adaptIter ? *ax : x, (PetscObject)adaptor, "-adapt_primal_sol_vec_view"));
797     /* PetscCall(DMAdaptorMonitor(adaptor));
798        Print iterate, memory used, DM, solution */
799     switch (adaptor->adaptCriterion) {
800     case DM_ADAPTATION_REFINE:
801       PetscCall(DMRefine(dm, comm, &odm));
802       PetscCheck(odm, comm, PETSC_ERR_ARG_INCOMP, "DMRefine() did not perform any refinement, cannot continue grid sequencing");
803       adapted = PETSC_TRUE;
804       break;
805     case DM_ADAPTATION_LABEL: {
806       /* Adapt DM
807            Create local solution
808            Reconstruct gradients (FVM) or solve adjoint equation (FEM)
809            Produce cellwise error indicator */
810       DM             edm, plex;
811       PetscFE        efe;
812       DMLabel        adaptLabel;
813       IS             refineIS, coarsenIS;
814       Vec            errVec;
815       DMPolytopeType ct;
816       PetscInt       nRefine, nCoarsen, cStart;
817 
818       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "adapt", &adaptLabel));
819 
820       // TODO Move this creation to PreAdapt
821       PetscCall(DMClone(dm, &edm));
822       PetscCall(DMConvert(edm, DMPLEX, &plex));
823       PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL));
824       PetscCall(DMPlexGetCellType(plex, cStart, &ct));
825       PetscCall(DMDestroy(&plex));
826       PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, 1, ct, 0, PETSC_DEFAULT, &efe));
827       PetscCall(PetscObjectSetName((PetscObject)efe, "Error"));
828       PetscCall(DMSetField(edm, 0, NULL, (PetscObject)efe));
829       PetscCall(PetscFEDestroy(&efe));
830       PetscCall(DMCreateDS(edm));
831       PetscCall(DMGetGlobalVector(edm, &errVec));
832       PetscCall(PetscObjectSetName((PetscObject)errVec, "Error Estimator"));
833 
834       PetscUseTypeMethod(adaptor, computeerrorindicator, locX, errVec);
835       PetscCall(VecViewFromOptions(errVec, (PetscObject)adaptor, "-adapt_error_vec_view"));
836 
837       // Compute IS from VecTagger
838       PetscCall(VecTaggerComputeIS(adaptor->refineTag, errVec, &refineIS, NULL));
839       PetscCall(VecTaggerComputeIS(adaptor->coarsenTag, errVec, &coarsenIS, NULL));
840       PetscCall(ISViewFromOptions(refineIS, (PetscObject)adaptor->refineTag, "-is_view"));
841       PetscCall(ISViewFromOptions(coarsenIS, (PetscObject)adaptor->coarsenTag, "-is_view"));
842       PetscCall(ISGetSize(refineIS, &nRefine));
843       PetscCall(ISGetSize(coarsenIS, &nCoarsen));
844       PetscCall(PetscInfo(adaptor, "DMAdaptor: numRefine %" PetscInt_FMT ", numCoarsen %" PetscInt_FMT "\n", nRefine, nCoarsen));
845       if (nRefine) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE, refineIS));
846       if (nCoarsen) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_COARSEN, coarsenIS));
847       PetscCall(ISDestroy(&coarsenIS));
848       PetscCall(ISDestroy(&refineIS));
849       PetscCall(DMRestoreGlobalVector(edm, &errVec));
850       PetscCall(DMDestroy(&edm));
851       // Adapt DM from label
852       if (nRefine || nCoarsen) {
853         char        oprefix[PETSC_MAX_PATH_LEN];
854         const char *p;
855         PetscBool   flg;
856 
857         PetscCall(PetscOptionsHasName(NULL, adaptor->hdr.prefix, "-adapt_vec_view", &flg));
858         if (flg) {
859           Vec ref;
860 
861           PetscCall(DMPlexCreateLabelField(dm, adaptLabel, &ref));
862           PetscCall(VecViewFromOptions(ref, (PetscObject)adaptor, "-adapt_vec_view"));
863           PetscCall(VecDestroy(&ref));
864         }
865 
866         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &p));
867         PetscCall(PetscStrncpy(oprefix, p, PETSC_MAX_PATH_LEN));
868         PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, "adapt_"));
869         PetscCall(DMAdaptLabel(dm, adaptLabel, &odm));
870         PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, oprefix));
871         PetscCall(PetscObjectSetOptionsPrefix((PetscObject)odm, oprefix));
872         adapted = PETSC_TRUE;
873       }
874       PetscCall(DMLabelDestroy(&adaptLabel));
875     } break;
876     case DM_ADAPTATION_METRIC: {
877       DM        dmGrad, dmHess, dmMetric, dmDet;
878       Vec       xGrad, xHess, metric, determinant;
879       PetscReal N;
880       DMLabel   bdLabel = NULL, rgLabel = NULL;
881       PetscBool higherOrder = PETSC_FALSE;
882       PetscInt  Nd          = coordDim * coordDim, f, vStart, vEnd;
883       void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
884 
885       PetscCall(PetscMalloc(1, &funcs));
886       funcs[0] = identityFunc;
887 
888       /*     Setup finite element spaces */
889       PetscCall(DMClone(dm, &dmGrad));
890       PetscCall(DMClone(dm, &dmHess));
891       PetscCheck(Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple fields not yet considered"); // TODO
892       for (f = 0; f < Nf; ++f) {
893         PetscFE         fe, feGrad, feHess;
894         PetscDualSpace  Q;
895         PetscSpace      space;
896         DM              K;
897         PetscQuadrature q;
898         PetscInt        Nc, qorder, p;
899         const char     *prefix;
900 
901         PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
902         PetscCall(PetscFEGetNumComponents(fe, &Nc));
903         PetscCheck(Nc <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Adaptation with multiple components not yet considered"); // TODO
904         PetscCall(PetscFEGetBasisSpace(fe, &space));
905         PetscCall(PetscSpaceGetDegree(space, NULL, &p));
906         if (p > 1) higherOrder = PETSC_TRUE;
907         PetscCall(PetscFEGetDualSpace(fe, &Q));
908         PetscCall(PetscDualSpaceGetDM(Q, &K));
909         PetscCall(DMPlexGetDepthStratum(K, 0, &vStart, &vEnd));
910         PetscCall(PetscFEGetQuadrature(fe, &q));
911         PetscCall(PetscQuadratureGetOrder(q, &qorder));
912         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)fe, &prefix));
913         PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmGrad), dim, Nc * coordDim, PETSC_TRUE, prefix, qorder, &feGrad));
914         PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)dmHess), dim, Nc * Nd, PETSC_TRUE, prefix, qorder, &feHess));
915         PetscCall(DMSetField(dmGrad, f, NULL, (PetscObject)feGrad));
916         PetscCall(DMSetField(dmHess, f, NULL, (PetscObject)feHess));
917         PetscCall(DMCreateDS(dmGrad));
918         PetscCall(DMCreateDS(dmHess));
919         PetscCall(PetscFEDestroy(&feGrad));
920         PetscCall(PetscFEDestroy(&feHess));
921       }
922       /*     Compute vertexwise gradients from cellwise gradients */
923       PetscCall(DMCreateLocalVector(dmGrad, &xGrad));
924       PetscCall(VecViewFromOptions(locX, NULL, "-sol_adapt_loc_pre_view"));
925       PetscCall(DMPlexComputeGradientClementInterpolant(dm, locX, xGrad));
926       PetscCall(VecViewFromOptions(xGrad, NULL, "-adapt_gradient_view"));
927       /*     Compute vertexwise Hessians from cellwise Hessians */
928       PetscCall(DMCreateLocalVector(dmHess, &xHess));
929       PetscCall(DMPlexComputeGradientClementInterpolant(dmGrad, xGrad, xHess));
930       PetscCall(VecViewFromOptions(xHess, NULL, "-adapt_hessian_view"));
931       PetscCall(VecDestroy(&xGrad));
932       PetscCall(DMDestroy(&dmGrad));
933       /*     Compute L-p normalized metric */
934       PetscCall(DMClone(dm, &dmMetric));
935       N = adaptor->Nadapt >= 0 ? adaptor->Nadapt : PetscPowRealInt(adaptor->refinementFactor, dim) * ((PetscReal)(vEnd - vStart));
936       if (adaptor->monitor) {
937         PetscMPIInt rank, size;
938         PetscCallMPI(MPI_Comm_rank(comm, &size));
939         PetscCallMPI(MPI_Comm_rank(comm, &rank));
940         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] N_orig: %" PetscInt_FMT " N_adapt: %g\n", rank, vEnd - vStart, (double)N));
941       }
942       PetscCall(DMPlexMetricSetTargetComplexity(dmMetric, (PetscReal)N));
943       if (higherOrder) {
944         /*   Project Hessian into P1 space, if required */
945         PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric));
946         PetscCall(DMProjectFieldLocal(dmMetric, 0.0, xHess, funcs, INSERT_ALL_VALUES, metric));
947         PetscCall(VecDestroy(&xHess));
948         xHess = metric;
949       }
950       PetscCall(PetscFree(funcs));
951       PetscCall(DMPlexMetricCreate(dmMetric, 0, &metric));
952       PetscCall(DMPlexMetricDeterminantCreate(dmMetric, 0, &determinant, &dmDet));
953       PetscCall(DMPlexMetricNormalize(dmMetric, xHess, PETSC_TRUE, PETSC_TRUE, metric, determinant));
954       PetscCall(VecDestroy(&determinant));
955       PetscCall(DMDestroy(&dmDet));
956       PetscCall(VecDestroy(&xHess));
957       PetscCall(DMDestroy(&dmHess));
958       /*     Adapt DM from metric */
959       PetscCall(DMGetLabel(dm, "marker", &bdLabel));
960       PetscCall(DMAdaptMetric(dm, metric, bdLabel, rgLabel, &odm));
961       adapted = PETSC_TRUE;
962       /*     Cleanup */
963       PetscCall(VecDestroy(&metric));
964       PetscCall(DMDestroy(&dmMetric));
965     } break;
966     default:
967       SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid adaptation type: %d", adaptor->adaptCriterion);
968     }
969     PetscCall(DMAdaptorPostAdapt(adaptor));
970     PetscCall(DMRestoreLocalVector(dm, &locX));
971     /* If DM was adapted, replace objects and recreate solution */
972     if (adapted) {
973       const char *name;
974 
975       PetscCall(PetscObjectGetName((PetscObject)dm, &name));
976       PetscCall(PetscObjectSetName((PetscObject)odm, name));
977       /* Reconfigure solver */
978       PetscCall(SNESReset(adaptor->snes));
979       PetscCall(SNESSetDM(adaptor->snes, odm));
980       PetscCall(DMAdaptorSetSolver(adaptor, adaptor->snes));
981       PetscCall(DMPlexSetSNESLocalFEM(odm, PETSC_FALSE, ctx));
982       PetscCall(SNESSetFromOptions(adaptor->snes));
983       /* Transfer system */
984       PetscCall(DMCopyDisc(dm, odm));
985       /* Transfer solution */
986       PetscCall(DMCreateGlobalVector(odm, &ox));
987       PetscCall(PetscObjectGetName((PetscObject)x, &name));
988       PetscCall(PetscObjectSetName((PetscObject)ox, name));
989       PetscCall(DMAdaptorTransferSolution(adaptor, dm, x, odm, ox));
990       /* Cleanup adaptivity info */
991       if (adaptIter > 0) PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_(comm)));
992       PetscCall(DMForestSetAdaptivityForest(dm, NULL)); /* clear internal references to the previous dm */
993       PetscCall(DMDestroy(&dm));
994       PetscCall(VecDestroy(&x));
995       *adm = odm;
996       *ax  = ox;
997     } else {
998       *adm      = dm;
999       *ax       = x;
1000       adaptIter = numAdapt;
1001     }
1002     if (adaptIter < numAdapt - 1) {
1003       PetscCall(DMViewFromOptions(odm, NULL, "-dm_adapt_iter_view"));
1004       PetscCall(VecViewFromOptions(ox, NULL, "-sol_adapt_iter_view"));
1005     }
1006   }
1007   PetscCall(DMViewFromOptions(*adm, NULL, "-dm_adapt_view"));
1008   PetscCall(VecViewFromOptions(*ax, NULL, "-sol_adapt_view"));
1009   PetscFunctionReturn(PETSC_SUCCESS);
1010 }
1011 
1012 /*@
1013   DMAdaptorAdapt - Creates a new `DM` that is adapted to the problem
1014 
1015   Not Collective
1016 
1017   Input Parameters:
1018 + adaptor  - The `DMAdaptor` object
1019 . x        - The global approximate solution
1020 - strategy - The adaptation strategy, see `DMAdaptationStrategy`
1021 
1022   Output Parameters:
1023 + adm - The adapted `DM`
1024 - ax  - The adapted solution
1025 
1026   Options Database Keys:
1027 + -snes_adapt <strategy> - initial, sequential, multigrid
1028 . -adapt_gradient_view   - View the Clement interpolant of the solution gradient
1029 . -adapt_hessian_view    - View the Clement interpolant of the solution Hessian
1030 - -adapt_metric_view     - View the metric tensor for adaptive mesh refinement
1031 
1032   Level: intermediate
1033 
1034 .seealso: [](ch_dmbase), `DMAdaptor`, `DMAdaptationStrategy`, `DMAdaptorSetSolver()`, `DMAdaptorCreate()`
1035 @*/
1036 PetscErrorCode DMAdaptorAdapt(DMAdaptor adaptor, Vec x, DMAdaptationStrategy strategy, DM *adm, Vec *ax)
1037 {
1038   PetscFunctionBegin;
1039   switch (strategy) {
1040   case DM_ADAPTATION_INITIAL:
1041     PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_FALSE, adm, ax));
1042     break;
1043   case DM_ADAPTATION_SEQUENTIAL:
1044     PetscCall(DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_TRUE, adm, ax));
1045     break;
1046   default:
1047     SETERRQ(PetscObjectComm((PetscObject)adaptor), PETSC_ERR_ARG_WRONG, "Unrecognized adaptation strategy %d", strategy);
1048   }
1049   PetscFunctionReturn(PETSC_SUCCESS);
1050 }
1051 
1052 /*@C
1053   DMAdaptorGetMixedSetupFunction - Get the function setting up the mixed problem, if it exists
1054 
1055   Not Collective
1056 
1057   Input Parameter:
1058 . adaptor - the `DMAdaptor`
1059 
1060   Output Parameter:
1061 . setupFunc - the function setting up the mixed problem, or `NULL`
1062 
1063   Level: advanced
1064 
1065 .seealso: `DMAdaptor`, `DMAdaptorSetMixedSetupFunction()`, `DMAdaptorAdapt()`
1066 @*/
1067 PetscErrorCode DMAdaptorGetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (**setupFunc)(DMAdaptor, DM))
1068 {
1069   PetscFunctionBegin;
1070   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
1071   PetscAssertPointer(setupFunc, 2);
1072   *setupFunc = adaptor->ops->mixedsetup;
1073   PetscFunctionReturn(PETSC_SUCCESS);
1074 }
1075 
1076 /*@C
1077   DMAdaptorSetMixedSetupFunction - Set the function setting up the mixed problem
1078 
1079   Not Collective
1080 
1081   Input Parameters:
1082 + adaptor   - the `DMAdaptor`
1083 - setupFunc - the function setting up the mixed problem
1084 
1085   Level: advanced
1086 
1087 .seealso: `DMAdaptor`, `DMAdaptorGetMixedSetupFunction()`, `DMAdaptorAdapt()`
1088 @*/
1089 PetscErrorCode DMAdaptorSetMixedSetupFunction(DMAdaptor adaptor, PetscErrorCode (*setupFunc)(DMAdaptor, DM))
1090 {
1091   PetscFunctionBegin;
1092   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
1093   PetscValidFunction(setupFunc, 2);
1094   adaptor->ops->mixedsetup = setupFunc;
1095   PetscFunctionReturn(PETSC_SUCCESS);
1096 }
1097 
1098 static PetscErrorCode DMAdaptorInitialize_Gradient(DMAdaptor adaptor)
1099 {
1100   PetscFunctionBegin;
1101   adaptor->ops->computeerrorindicator     = DMAdaptorComputeErrorIndicator_Gradient;
1102   adaptor->ops->computecellerrorindicator = DMAdaptorComputeCellErrorIndicator_Gradient;
1103   PetscFunctionReturn(PETSC_SUCCESS);
1104 }
1105 
1106 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Gradient(DMAdaptor adaptor)
1107 {
1108   PetscFunctionBegin;
1109   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
1110   adaptor->data = NULL;
1111 
1112   PetscCall(DMAdaptorInitialize_Gradient(adaptor));
1113   PetscFunctionReturn(PETSC_SUCCESS);
1114 }
1115 
1116 static PetscErrorCode DMAdaptorInitialize_Flux(DMAdaptor adaptor)
1117 {
1118   PetscFunctionBegin;
1119   adaptor->ops->computeerrorindicator = DMAdaptorComputeErrorIndicator_Flux;
1120   PetscFunctionReturn(PETSC_SUCCESS);
1121 }
1122 
1123 PETSC_EXTERN PetscErrorCode DMAdaptorCreate_Flux(DMAdaptor adaptor)
1124 {
1125   PetscFunctionBegin;
1126   PetscValidHeaderSpecific(adaptor, DMADAPTOR_CLASSID, 1);
1127   adaptor->data = NULL;
1128 
1129   PetscCall(DMAdaptorInitialize_Flux(adaptor));
1130   PetscFunctionReturn(PETSC_SUCCESS);
1131 }
1132