xref: /petsc/src/dm/interface/dm.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375) !
1 #include <petscvec.h>
2 #include <petsc/private/dmimpl.h>      /*I      "petscdm.h"          I*/
3 #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"     I*/
4 #include <petsc/private/petscdsimpl.h> /*I      "petscds.h"     I*/
5 #include <petscdmplex.h>
6 #include <petscdmceed.h>
7 #include <petscdmfield.h>
8 #include <petscsf.h>
9 #include <petscds.h>
10 
11 #ifdef PETSC_HAVE_LIBCEED
12   #include <petscfeceed.h>
13 #endif
14 
15 PetscClassId DM_CLASSID;
16 PetscClassId DMLABEL_CLASSID;
17 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_View, DM_AdaptInterpolator, DM_ProjectFunction;
18 
19 const char *const DMBoundaryTypes[]          = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
20 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "LOWER_BOUND", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "UPPER_BOUND", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType",
21                                                 "DM_BC_",  NULL};
22 const char *const DMBlockingTypes[]          = {"TOPOLOGICAL_POINT", "FIELD_NODE", "DMBlockingType", "DM_BLOCKING_", NULL};
23 const char *const DMPolytopeTypes[] =
24   {"vertex",  "segment",      "tensor_segment", "triangle", "quadrilateral",  "tensor_quad",  "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell",
25    "unknown", "unknown_cell", "unknown_face",   "invalid",  "DMPolytopeType", "DM_POLYTOPE_", NULL};
26 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
27 
28 /*@
29   DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
30   algebraic solvers, time integrators, and optimization algorithms in PETSc.
31 
32   Collective
33 
34   Input Parameter:
35 . comm - The communicator for the `DM` object
36 
37   Output Parameter:
38 . dm - The `DM` object
39 
40   Level: beginner
41 
42   Notes:
43   See `DMType` for a brief summary of available `DM`.
44 
45   The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
46   error when you try to use the `dm`.
47 
48   `DM` is an orphan initialism or orphan acronym, the letters have no meaning and never did.
49 
50 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
51 @*/
DMCreate(MPI_Comm comm,DM * dm)52 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
53 {
54   DM      v;
55   PetscDS ds;
56 
57   PetscFunctionBegin;
58   PetscAssertPointer(dm, 2);
59 
60   PetscCall(DMInitializePackage());
61   PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView));
62   ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
63   v->setupcalled                          = PETSC_FALSE;
64   v->setfromoptionscalled                 = PETSC_FALSE;
65   v->ltogmap                              = NULL;
66   v->bind_below                           = 0;
67   v->bs                                   = 1;
68   v->coloringtype                         = IS_COLORING_GLOBAL;
69   PetscCall(PetscSFCreate(comm, &v->sf));
70   PetscCall(PetscSFCreate(comm, &v->sectionSF));
71   v->labels                    = NULL;
72   v->adjacency[0]              = PETSC_FALSE;
73   v->adjacency[1]              = PETSC_TRUE;
74   v->depthLabel                = NULL;
75   v->celltypeLabel             = NULL;
76   v->localSection              = NULL;
77   v->globalSection             = NULL;
78   v->defaultConstraint.section = NULL;
79   v->defaultConstraint.mat     = NULL;
80   v->defaultConstraint.bias    = NULL;
81   v->coordinates[0].dim        = PETSC_DEFAULT;
82   v->coordinates[1].dim        = PETSC_DEFAULT;
83   v->sparseLocalize            = PETSC_TRUE;
84   v->dim                       = PETSC_DETERMINE;
85   PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
86   PetscCall(DMSetRegionDS(v, NULL, NULL, ds, NULL));
87   PetscCall(PetscDSDestroy(&ds));
88   PetscCall(PetscHMapAuxCreate(&v->auxData));
89   v->dmBC              = NULL;
90   v->coarseMesh        = NULL;
91   v->outputSequenceNum = -1;
92   v->outputSequenceVal = 0.0;
93   PetscCall(DMSetVecType(v, VECSTANDARD));
94   PetscCall(DMSetMatType(v, MATAIJ));
95 
96   *dm = v;
97   PetscFunctionReturn(PETSC_SUCCESS);
98 }
99 
100 /*@
101   DMClone - Creates a `DM` object with the same topology as the original.
102 
103   Collective
104 
105   Input Parameter:
106 . dm - The original `DM` object
107 
108   Output Parameter:
109 . newdm - The new `DM` object
110 
111   Level: beginner
112 
113   Notes:
114   For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
115   `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
116   share the `PetscSection` of the original `DM`.
117 
118   The clone is considered set up if the original has been set up.
119 
120   Use `DMConvert()` for a general way to create new `DM` from a given `DM`
121 
122 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMConvert()`
123 @*/
DMClone(DM dm,DM * newdm)124 PetscErrorCode DMClone(DM dm, DM *newdm)
125 {
126   PetscSF              sf;
127   Vec                  coords;
128   void                *ctx;
129   MatOrderingType      otype;
130   DMReorderDefaultFlag flg;
131   PetscInt             dim, cdim, i;
132 
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
135   PetscAssertPointer(newdm, 2);
136   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), newdm));
137   PetscCall(DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL));
138   (*newdm)->leveldown     = dm->leveldown;
139   (*newdm)->levelup       = dm->levelup;
140   (*newdm)->prealloc_only = dm->prealloc_only;
141   (*newdm)->prealloc_skip = dm->prealloc_skip;
142   PetscCall(PetscFree((*newdm)->vectype));
143   PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype));
144   PetscCall(PetscFree((*newdm)->mattype));
145   PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype));
146   PetscCall(DMGetDimension(dm, &dim));
147   PetscCall(DMSetDimension(*newdm, dim));
148   PetscTryTypeMethod(dm, clone, newdm);
149   (*newdm)->setupcalled = dm->setupcalled;
150   PetscCall(DMGetPointSF(dm, &sf));
151   PetscCall(DMSetPointSF(*newdm, sf));
152   PetscCall(DMGetApplicationContext(dm, &ctx));
153   PetscCall(DMSetApplicationContext(*newdm, ctx));
154   PetscCall(DMReorderSectionGetDefault(dm, &flg));
155   PetscCall(DMReorderSectionSetDefault(*newdm, flg));
156   PetscCall(DMReorderSectionGetType(dm, &otype));
157   PetscCall(DMReorderSectionSetType(*newdm, otype));
158   for (i = 0; i < 2; ++i) {
159     if (dm->coordinates[i].dm) {
160       DM           ncdm;
161       PetscSection cs;
162       PetscInt     pEnd = -1, pEndMax = -1;
163 
164       PetscCall(DMGetLocalSection(dm->coordinates[i].dm, &cs));
165       if (cs) PetscCall(PetscSectionGetChart(cs, NULL, &pEnd));
166       PetscCallMPI(MPIU_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
167       if (pEndMax >= 0) {
168         PetscCall(DMClone(dm->coordinates[i].dm, &ncdm));
169         PetscCall(DMCopyDisc(dm->coordinates[i].dm, ncdm));
170         PetscCall(DMSetLocalSection(ncdm, cs));
171         if (dm->coordinates[i].dm->periodic.setup) {
172           ncdm->periodic.setup = dm->coordinates[i].dm->periodic.setup;
173           PetscCall(ncdm->periodic.setup(ncdm));
174         }
175         if (i) PetscCall(DMSetCellCoordinateDM(*newdm, ncdm));
176         else PetscCall(DMSetCoordinateDM(*newdm, ncdm));
177         PetscCall(DMDestroy(&ncdm));
178       }
179     }
180   }
181   PetscCall(DMGetCoordinateDim(dm, &cdim));
182   PetscCall(DMSetCoordinateDim(*newdm, cdim));
183   PetscCall(DMGetCoordinatesLocal(dm, &coords));
184   if (coords) {
185     PetscCall(DMSetCoordinatesLocal(*newdm, coords));
186   } else {
187     PetscCall(DMGetCoordinates(dm, &coords));
188     if (coords) PetscCall(DMSetCoordinates(*newdm, coords));
189   }
190   PetscCall(DMGetCellCoordinatesLocal(dm, &coords));
191   if (coords) {
192     PetscCall(DMSetCellCoordinatesLocal(*newdm, coords));
193   } else {
194     PetscCall(DMGetCellCoordinates(dm, &coords));
195     if (coords) PetscCall(DMSetCellCoordinates(*newdm, coords));
196   }
197   {
198     const PetscReal *maxCell, *Lstart, *L;
199 
200     PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
201     PetscCall(DMSetPeriodicity(*newdm, maxCell, Lstart, L));
202   }
203   {
204     PetscBool useCone, useClosure;
205 
206     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure));
207     PetscCall(DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure));
208   }
209   PetscFunctionReturn(PETSC_SUCCESS);
210 }
211 
212 /*@
213   DMSetVecType - Sets the type of vector to be created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
214 
215   Logically Collective
216 
217   Input Parameters:
218 + dm    - initial distributed array
219 - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`
220 
221   Options Database Key:
222 . -dm_vec_type ctype - the type of vector to create
223 
224   Level: intermediate
225 
226 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
227           `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
228 @*/
DMSetVecType(DM dm,VecType ctype)229 PetscErrorCode DMSetVecType(DM dm, VecType ctype)
230 {
231   char *tmp;
232 
233   PetscFunctionBegin;
234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
235   PetscAssertPointer(ctype, 2);
236   tmp = (char *)dm->vectype;
237   PetscCall(PetscStrallocpy(ctype, (char **)&dm->vectype));
238   PetscCall(PetscFree(tmp));
239   PetscFunctionReturn(PETSC_SUCCESS);
240 }
241 
242 /*@
243   DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
244 
245   Logically Collective
246 
247   Input Parameter:
248 . da - initial distributed array
249 
250   Output Parameter:
251 . ctype - the vector type
252 
253   Level: intermediate
254 
255 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
256 @*/
DMGetVecType(DM da,VecType * ctype)257 PetscErrorCode DMGetVecType(DM da, VecType *ctype)
258 {
259   PetscFunctionBegin;
260   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
261   *ctype = da->vectype;
262   PetscFunctionReturn(PETSC_SUCCESS);
263 }
264 
265 /*@
266   VecGetDM - Gets the `DM` defining the data layout of the vector
267 
268   Not Collective
269 
270   Input Parameter:
271 . v - The `Vec`
272 
273   Output Parameter:
274 . dm - The `DM`
275 
276   Level: intermediate
277 
278   Note:
279   A `Vec` may not have a `DM` associated with it.
280 
281 .seealso: [](ch_dmbase), `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
282 @*/
VecGetDM(Vec v,DM * dm)283 PetscErrorCode VecGetDM(Vec v, DM *dm)
284 {
285   PetscFunctionBegin;
286   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
287   PetscAssertPointer(dm, 2);
288   PetscCall(PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm));
289   PetscFunctionReturn(PETSC_SUCCESS);
290 }
291 
292 /*@
293   VecSetDM - Sets the `DM` defining the data layout of the vector.
294 
295   Not Collective
296 
297   Input Parameters:
298 + v  - The `Vec`
299 - dm - The `DM`
300 
301   Level: developer
302 
303   Notes:
304   This is rarely used, generally one uses `DMGetLocalVector()` or  `DMGetGlobalVector()` to create a vector associated with a given `DM`
305 
306   This is NOT the same as `DMCreateGlobalVector()` since it does not change the view methods or perform other customization, but merely sets the `DM` member.
307 
308 .seealso: [](ch_dmbase), `DM`, `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
309 @*/
VecSetDM(Vec v,DM dm)310 PetscErrorCode VecSetDM(Vec v, DM dm)
311 {
312   PetscFunctionBegin;
313   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
314   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
315   PetscCall(PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm));
316   PetscFunctionReturn(PETSC_SUCCESS);
317 }
318 
319 /*@
320   DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
321 
322   Logically Collective
323 
324   Input Parameters:
325 + dm    - the `DM` context
326 - ctype - the matrix type
327 
328   Options Database Key:
329 . -dm_is_coloring_type - global or local
330 
331   Level: intermediate
332 
333 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
334           `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
335 @*/
DMSetISColoringType(DM dm,ISColoringType ctype)336 PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
337 {
338   PetscFunctionBegin;
339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
340   dm->coloringtype = ctype;
341   PetscFunctionReturn(PETSC_SUCCESS);
342 }
343 
344 /*@
345   DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
346 
347   Logically Collective
348 
349   Input Parameter:
350 . dm - the `DM` context
351 
352   Output Parameter:
353 . ctype - the matrix type
354 
355   Options Database Key:
356 . -dm_is_coloring_type - global or local
357 
358   Level: intermediate
359 
360 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
361           `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
362 @*/
DMGetISColoringType(DM dm,ISColoringType * ctype)363 PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
364 {
365   PetscFunctionBegin;
366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
367   *ctype = dm->coloringtype;
368   PetscFunctionReturn(PETSC_SUCCESS);
369 }
370 
371 /*@
372   DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`
373 
374   Logically Collective
375 
376   Input Parameters:
377 + dm    - the `DM` context
378 - ctype - the matrix type, for example `MATMPIAIJ`
379 
380   Options Database Key:
381 . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij
382 
383   Level: intermediate
384 
385 .seealso: [](ch_dmbase), `DM`, `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
386 @*/
DMSetMatType(DM dm,MatType ctype)387 PetscErrorCode DMSetMatType(DM dm, MatType ctype)
388 {
389   char *tmp;
390 
391   PetscFunctionBegin;
392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
393   PetscAssertPointer(ctype, 2);
394   tmp = (char *)dm->mattype;
395   PetscCall(PetscStrallocpy(ctype, (char **)&dm->mattype));
396   PetscCall(PetscFree(tmp));
397   PetscFunctionReturn(PETSC_SUCCESS);
398 }
399 
400 /*@
401   DMGetMatType - Gets the type of matrix that would be created with `DMCreateMatrix()`
402 
403   Logically Collective
404 
405   Input Parameter:
406 . dm - the `DM` context
407 
408   Output Parameter:
409 . ctype - the matrix type
410 
411   Level: intermediate
412 
413 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`
414 @*/
DMGetMatType(DM dm,MatType * ctype)415 PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
416 {
417   PetscFunctionBegin;
418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
419   *ctype = dm->mattype;
420   PetscFunctionReturn(PETSC_SUCCESS);
421 }
422 
423 /*@
424   MatGetDM - Gets the `DM` defining the data layout of the matrix
425 
426   Not Collective
427 
428   Input Parameter:
429 . A - The `Mat`
430 
431   Output Parameter:
432 . dm - The `DM`
433 
434   Level: intermediate
435 
436   Note:
437   A matrix may not have a `DM` associated with it
438 
439   Developer Note:
440   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation
441 
442 .seealso: [](ch_dmbase), `DM`, `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
443 @*/
MatGetDM(Mat A,DM * dm)444 PetscErrorCode MatGetDM(Mat A, DM *dm)
445 {
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
448   PetscAssertPointer(dm, 2);
449   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm));
450   PetscFunctionReturn(PETSC_SUCCESS);
451 }
452 
453 /*@
454   MatSetDM - Sets the `DM` defining the data layout of the matrix
455 
456   Not Collective
457 
458   Input Parameters:
459 + A  - The `Mat`
460 - dm - The `DM`
461 
462   Level: developer
463 
464   Note:
465   This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`
466 
467   Developer Note:
468   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
469   the `Mat` through a `PetscObjectCompose()` operation
470 
471 .seealso: [](ch_dmbase), `DM`, `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
472 @*/
MatSetDM(Mat A,DM dm)473 PetscErrorCode MatSetDM(Mat A, DM dm)
474 {
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
477   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
478   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm));
479   PetscFunctionReturn(PETSC_SUCCESS);
480 }
481 
482 /*@
483   DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database
484 
485   Logically Collective
486 
487   Input Parameters:
488 + dm     - the `DM` context
489 - prefix - the prefix to prepend
490 
491   Level: advanced
492 
493   Note:
494   A hyphen (-) must NOT be given at the beginning of the prefix name.
495   The first character of all runtime options is AUTOMATICALLY the hyphen.
496 
497 .seealso: [](ch_dmbase), `DM`, `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
498 @*/
DMSetOptionsPrefix(DM dm,const char prefix[])499 PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
500 {
501   PetscFunctionBegin;
502   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
503   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
504   if (dm->sf) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix));
505   if (dm->sectionSF) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix));
506   PetscFunctionReturn(PETSC_SUCCESS);
507 }
508 
509 /*@
510   DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
511   `DM` options in the options database.
512 
513   Logically Collective
514 
515   Input Parameters:
516 + dm     - the `DM` context
517 - prefix - the string to append to the current prefix
518 
519   Level: advanced
520 
521   Note:
522   If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
523   A hyphen (-) must NOT be given at the beginning of the prefix name.
524   The first character of all runtime options is AUTOMATICALLY the hyphen.
525 
526 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
527 @*/
DMAppendOptionsPrefix(DM dm,const char prefix[])528 PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
529 {
530   PetscFunctionBegin;
531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
532   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix));
533   PetscFunctionReturn(PETSC_SUCCESS);
534 }
535 
536 /*@
537   DMGetOptionsPrefix - Gets the prefix used for searching for all
538   DM options in the options database.
539 
540   Not Collective
541 
542   Input Parameter:
543 . dm - the `DM` context
544 
545   Output Parameter:
546 . prefix - pointer to the prefix string used is returned
547 
548   Level: advanced
549 
550 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
551 @*/
DMGetOptionsPrefix(DM dm,const char * prefix[])552 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
553 {
554   PetscFunctionBegin;
555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
556   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix));
557   PetscFunctionReturn(PETSC_SUCCESS);
558 }
559 
DMCountNonCyclicReferences_Internal(DM dm,PetscBool recurseCoarse,PetscBool recurseFine,PetscInt * ncrefct)560 static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
561 {
562   PetscInt refct = ((PetscObject)dm)->refct;
563 
564   PetscFunctionBegin;
565   *ncrefct = 0;
566   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
567     refct--;
568     if (recurseCoarse) {
569       PetscInt coarseCount;
570 
571       PetscCall(DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount));
572       refct += coarseCount;
573     }
574   }
575   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
576     refct--;
577     if (recurseFine) {
578       PetscInt fineCount;
579 
580       PetscCall(DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount));
581       refct += fineCount;
582     }
583   }
584   *ncrefct = refct;
585   PetscFunctionReturn(PETSC_SUCCESS);
586 }
587 
588 /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
DMCountNonCyclicReferences(PetscObject dm,PetscInt * ncrefct)589 PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
590 {
591   PetscFunctionBegin;
592   PetscCall(DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct));
593   PetscFunctionReturn(PETSC_SUCCESS);
594 }
595 
DMDestroyLabelLinkList_Internal(DM dm)596 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
597 {
598   DMLabelLink next = dm->labels;
599 
600   PetscFunctionBegin;
601   /* destroy the labels */
602   while (next) {
603     DMLabelLink tmp = next->next;
604 
605     if (next->label == dm->depthLabel) dm->depthLabel = NULL;
606     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
607     PetscCall(DMLabelDestroy(&next->label));
608     PetscCall(PetscFree(next));
609     next = tmp;
610   }
611   dm->labels = NULL;
612   PetscFunctionReturn(PETSC_SUCCESS);
613 }
614 
DMDestroyCoordinates_Private(DMCoordinates * c)615 static PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
616 {
617   PetscFunctionBegin;
618   c->dim = PETSC_DEFAULT;
619   PetscCall(DMDestroy(&c->dm));
620   PetscCall(VecDestroy(&c->x));
621   PetscCall(VecDestroy(&c->xl));
622   PetscCall(DMFieldDestroy(&c->field));
623   PetscFunctionReturn(PETSC_SUCCESS);
624 }
625 
626 /*@
627   DMDestroy - Destroys a `DM`.
628 
629   Collective
630 
631   Input Parameter:
632 . dm - the `DM` object to destroy
633 
634   Level: developer
635 
636 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
637 @*/
DMDestroy(DM * dm)638 PetscErrorCode DMDestroy(DM *dm)
639 {
640   PetscInt cnt;
641 
642   PetscFunctionBegin;
643   if (!*dm) PetscFunctionReturn(PETSC_SUCCESS);
644   PetscValidHeaderSpecific(*dm, DM_CLASSID, 1);
645 
646   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
647   PetscCall(DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt));
648   --((PetscObject)*dm)->refct;
649   if (--cnt > 0) {
650     *dm = NULL;
651     PetscFunctionReturn(PETSC_SUCCESS);
652   }
653   if (((PetscObject)*dm)->refct < 0) PetscFunctionReturn(PETSC_SUCCESS);
654   ((PetscObject)*dm)->refct = 0;
655 
656   PetscCall(DMClearGlobalVectors(*dm));
657   PetscCall(DMClearLocalVectors(*dm));
658   PetscCall(DMClearNamedGlobalVectors(*dm));
659   PetscCall(DMClearNamedLocalVectors(*dm));
660 
661   /* Destroy the list of hooks */
662   {
663     DMCoarsenHookLink link, next;
664     for (link = (*dm)->coarsenhook; link; link = next) {
665       next = link->next;
666       PetscCall(PetscFree(link));
667     }
668     (*dm)->coarsenhook = NULL;
669   }
670   {
671     DMRefineHookLink link, next;
672     for (link = (*dm)->refinehook; link; link = next) {
673       next = link->next;
674       PetscCall(PetscFree(link));
675     }
676     (*dm)->refinehook = NULL;
677   }
678   {
679     DMSubDomainHookLink link, next;
680     for (link = (*dm)->subdomainhook; link; link = next) {
681       next = link->next;
682       PetscCall(PetscFree(link));
683     }
684     (*dm)->subdomainhook = NULL;
685   }
686   {
687     DMGlobalToLocalHookLink link, next;
688     for (link = (*dm)->gtolhook; link; link = next) {
689       next = link->next;
690       PetscCall(PetscFree(link));
691     }
692     (*dm)->gtolhook = NULL;
693   }
694   {
695     DMLocalToGlobalHookLink link, next;
696     for (link = (*dm)->ltoghook; link; link = next) {
697       next = link->next;
698       PetscCall(PetscFree(link));
699     }
700     (*dm)->ltoghook = NULL;
701   }
702   /* Destroy the work arrays */
703   {
704     DMWorkLink link, next;
705     PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out %p %p", (void *)(*dm)->workout, (*dm)->workout->mem);
706     for (link = (*dm)->workin; link; link = next) {
707       next = link->next;
708       PetscCall(PetscFree(link->mem));
709       PetscCall(PetscFree(link));
710     }
711     (*dm)->workin = NULL;
712   }
713   /* destroy the labels */
714   PetscCall(DMDestroyLabelLinkList_Internal(*dm));
715   /* destroy the fields */
716   PetscCall(DMClearFields(*dm));
717   /* destroy the boundaries */
718   {
719     DMBoundary next = (*dm)->boundary;
720     while (next) {
721       DMBoundary b = next;
722 
723       next = b->next;
724       PetscCall(PetscFree(b));
725     }
726   }
727 
728   PetscCall(PetscObjectDestroy(&(*dm)->dmksp));
729   PetscCall(PetscObjectDestroy(&(*dm)->dmsnes));
730   PetscCall(PetscObjectDestroy(&(*dm)->dmts));
731 
732   if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx));
733   PetscCall(MatFDColoringDestroy(&(*dm)->fd));
734   PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap));
735   PetscCall(PetscFree((*dm)->vectype));
736   PetscCall(PetscFree((*dm)->mattype));
737 
738   PetscCall(PetscSectionDestroy(&(*dm)->localSection));
739   PetscCall(PetscSectionDestroy(&(*dm)->globalSection));
740   PetscCall(PetscFree((*dm)->reorderSectionType));
741   PetscCall(PetscLayoutDestroy(&(*dm)->map));
742   PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section));
743   PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat));
744   PetscCall(PetscSFDestroy(&(*dm)->sf));
745   PetscCall(PetscSFDestroy(&(*dm)->sectionSF));
746   if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural));
747   PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration));
748   PetscCall(DMClearAuxiliaryVec(*dm));
749   PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData));
750   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL));
751 
752   PetscCall(DMDestroy(&(*dm)->coarseMesh));
753   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL));
754   PetscCall(DMDestroy(&(*dm)->fineMesh));
755   PetscCall(PetscFree((*dm)->Lstart));
756   PetscCall(PetscFree((*dm)->L));
757   PetscCall(PetscFree((*dm)->maxCell));
758   PetscCall(PetscFree2((*dm)->nullspaceConstructors, (*dm)->nearnullspaceConstructors));
759   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0]));
760   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1]));
761   if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx));
762   PetscCall(DMDestroy(&(*dm)->transformDM));
763   PetscCall(VecDestroy(&(*dm)->transform));
764   for (PetscInt i = 0; i < (*dm)->periodic.num_affines; i++) {
765     PetscCall(VecScatterDestroy(&(*dm)->periodic.affine_to_local[i]));
766     PetscCall(VecDestroy(&(*dm)->periodic.affine[i]));
767   }
768   if ((*dm)->periodic.num_affines > 0) PetscCall(PetscFree2((*dm)->periodic.affine_to_local, (*dm)->periodic.affine));
769 
770   PetscCall(DMClearDS(*dm));
771   PetscCall(DMDestroy(&(*dm)->dmBC));
772   /* if memory was published with SAWs then destroy it */
773   PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm));
774 
775   PetscTryTypeMethod(*dm, destroy);
776   PetscCall(DMMonitorCancel(*dm));
777   PetscCall(DMCeedDestroy(&(*dm)->dmceed));
778 #ifdef PETSC_HAVE_LIBCEED
779   PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict));
780   PetscCallCEED(CeedDestroy(&(*dm)->ceed));
781 #endif
782   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
783   PetscCall(PetscHeaderDestroy(dm));
784   PetscFunctionReturn(PETSC_SUCCESS);
785 }
786 
787 /*@
788   DMSetUp - sets up the data structures inside a `DM` object
789 
790   Collective
791 
792   Input Parameter:
793 . dm - the `DM` object to setup
794 
795   Level: intermediate
796 
797   Note:
798   This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
799 
800 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
801 @*/
DMSetUp(DM dm)802 PetscErrorCode DMSetUp(DM dm)
803 {
804   PetscFunctionBegin;
805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
806   if (dm->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
807   PetscTryTypeMethod(dm, setup);
808   dm->setupcalled = PETSC_TRUE;
809   PetscFunctionReturn(PETSC_SUCCESS);
810 }
811 
812 /*@
813   DMSetFromOptions - sets parameters in a `DM` from the options database
814 
815   Collective
816 
817   Input Parameter:
818 . dm - the `DM` object to set options for
819 
820   Options Database Keys:
821 + -dm_preallocate_only                               - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
822 . -dm_vec_type <type>                                - type of vector to create inside `DM`
823 . -dm_mat_type <type>                                - type of matrix to create inside `DM`
824 . -dm_is_coloring_type                               - <global or local>
825 . -dm_bind_below <n>                                 - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA`
826 . -dm_plex_option_phases <ph0_, ph1_, ...>           - List of prefixes for option processing phases
827 . -dm_plex_filename <str>                            - File containing a mesh
828 . -dm_plex_boundary_filename <str>                   - File containing a mesh boundary
829 . -dm_plex_name <str>                                - Name of the mesh in the file
830 . -dm_plex_shape <shape>                             - The domain shape, such as `BOX`, `SPHERE`, etc.
831 . -dm_plex_cell <ct>                                 - Cell shape
832 . -dm_plex_reference_cell_domain <bool>              - Use a reference cell domain
833 . -dm_plex_dim <dim>                                 - Set the topological dimension
834 . -dm_plex_simplex <bool>                            - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
835 . -dm_plex_interpolate <bool>                        - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
836 . -dm_plex_orient <bool>                             - `PETSC_TRUE` turns on topological orientation (flipping edges and faces)
837 . -dm_plex_scale <sc>                                - Scale factor for mesh coordinates
838 . -dm_coord_remap <bool>                             - Map coordinates using a function
839 . -dm_plex_coordinate_dim <dim>                      - Change the coordinate dimension of a mesh (usually given with cdm_ prefix)
840 . -dm_coord_map <mapname>                            - Select a builtin coordinate map
841 . -dm_coord_map_params <p0,p1,p2,...>                - Set coordinate mapping parameters
842 . -dm_plex_box_faces <m,n,p>                         - Number of faces along each dimension
843 . -dm_plex_box_lower <x,y,z>                         - Specify lower-left-bottom coordinates for the box
844 . -dm_plex_box_upper <x,y,z>                         - Specify upper-right-top coordinates for the box
845 . -dm_plex_box_bd <bx,by,bz>                         - Specify the `DMBoundaryType` for each direction
846 . -dm_plex_sphere_radius <r>                         - The sphere radius
847 . -dm_plex_ball_radius <r>                           - Radius of the ball
848 . -dm_plex_cylinder_bd <bz>                          - Boundary type in the z direction
849 . -dm_plex_cylinder_num_wedges <n>                   - Number of wedges around the cylinder
850 . -dm_plex_reorder <order>                           - Reorder the mesh using the specified algorithm
851 . -dm_refine_pre <n>                                 - The number of refinements before distribution
852 . -dm_refine_uniform_pre <bool>                      - Flag for uniform refinement before distribution
853 . -dm_refine_volume_limit_pre <v>                    - The maximum cell volume after refinement before distribution
854 . -dm_refine <n>                                     - The number of refinements after distribution
855 . -dm_extrude <l>                                    - Activate extrusion and specify the number of layers to extrude
856 . -dm_plex_save_transform <bool>                     - Save the `DMPlexTransform` that produced this mesh
857 . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
858 . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
859 . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
860 . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
861 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
862 . -dm_plex_create_fv_ghost_cells                     - Flag to create finite volume ghost cells on the boundary
863 . -dm_plex_fv_ghost_cells_label <name>               - Label name for ghost cells boundary
864 . -dm_distribute <bool>                              - Flag to redistribute a mesh among processes
865 . -dm_distribute_overlap <n>                         - The size of the overlap halo
866 . -dm_plex_adj_cone <bool>                           - Set adjacency direction
867 . -dm_plex_adj_closure <bool>                        - Set adjacency size
868 . -dm_plex_use_ceed <bool>                           - Use LibCEED as the FEM backend
869 . -dm_plex_check_symmetry                            - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
870 . -dm_plex_check_skeleton                            - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
871 . -dm_plex_check_faces                               - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - `DMPlexCheckFaces()`
872 . -dm_plex_check_geometry                            - Check that cells have positive volume - `DMPlexCheckGeometry()`
873 . -dm_plex_check_pointsf                             - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
874 . -dm_plex_check_interface_cones                     - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
875 - -dm_plex_check_all                                 - Perform all the checks above
876 
877   Level: intermediate
878 
879   Note:
880   For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called.
881 
882 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
883          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
884          `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()`
885 @*/
DMSetFromOptions(DM dm)886 PetscErrorCode DMSetFromOptions(DM dm)
887 {
888   char      typeName[256];
889   PetscBool flg;
890 
891   PetscFunctionBegin;
892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
893   dm->setfromoptionscalled = PETSC_TRUE;
894   if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf));
895   if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF));
896   if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm));
897   PetscObjectOptionsBegin((PetscObject)dm);
898   PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL));
899   PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg));
900   if (flg) PetscCall(DMSetVecType(dm, typeName));
901   PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg));
902   if (flg) PetscCall(DMSetMatType(dm, typeName));
903   PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL));
904   PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL));
905   PetscCall(PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg));
906   PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL));
907   PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
908   /* process any options handlers added with PetscObjectAddOptionsHandler() */
909   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject));
910   PetscOptionsEnd();
911   PetscFunctionReturn(PETSC_SUCCESS);
912 }
913 
914 /*@
915   DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
916 
917   Collective
918 
919   Input Parameters:
920 + dm   - the `DM` object
921 . obj  - optional object that provides the prefix for the options database (if `NULL` then the prefix in `obj` is used)
922 - name - option string that is used to activate viewing
923 
924   Level: intermediate
925 
926   Note:
927   See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
928 
929 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`
930 @*/
DMViewFromOptions(DM dm,PeOp PetscObject obj,const char name[])931 PetscErrorCode DMViewFromOptions(DM dm, PeOp PetscObject obj, const char name[])
932 {
933   PetscFunctionBegin;
934   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
935   PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name));
936   PetscFunctionReturn(PETSC_SUCCESS);
937 }
938 
939 /*@
940   DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
941   save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
942 
943   Collective
944 
945   Input Parameters:
946 + dm - the `DM` object to view
947 - v  - the viewer
948 
949   Options Database Keys:
950 + -view_pyvista_warp <f>                 - Warps the mesh by the active scalar with factor f
951 . -view_pyvista_clip <xl,xu,yl,yu,zl,zu> - Defines the clipping box
952 . -dm_view_draw_line_color <int>         - Specify the X-window color for cell borders
953 . -dm_view_draw_cell_color <int>         - Specify the X-window color for cells
954 - -dm_view_draw_affine <bool>            - Flag to ignore high-order edges
955 
956   Level: beginner
957 
958   Notes:
959 
960   `PetscViewer` = `PETSCVIEWERHDF5` i.e. HDF5 format can be used with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` to save multiple `DMPLEX`
961   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
962   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
963 
964   `PetscViewer` = `PETSCVIEWEREXODUSII` i.e. ExodusII format assumes that element blocks (mapped to "Cell sets" labels)
965   consists of sequentially numbered cells.
966 
967   If `dm` has been distributed, only the part of the `DM` on MPI rank 0 (including "ghost" cells and vertices) will be written.
968 
969   Only TRI, TET, QUAD, and HEX cells are supported in ExodusII.
970 
971   `DMPLEX` only represents geometry while most post-processing software expect that a mesh also provides information on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2.
972   The order of the mesh shall be set using `PetscViewerExodusIISetOrder()`
973 
974   Variable names can be set and queried using `PetscViewerExodusII[Set/Get][Nodal/Zonal]VariableNames[s]`.
975 
976 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
977 @*/
DMView(DM dm,PetscViewer v)978 PetscErrorCode DMView(DM dm, PetscViewer v)
979 {
980   PetscBool         isbinary;
981   PetscMPIInt       size;
982   PetscViewerFormat format;
983 
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
986   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v));
987   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
988   /* Ideally, we would like to have this test on.
989      However, it currently breaks socket viz via GLVis.
990      During DMView(parallel_mesh,glvis_viewer), each
991      process opens a sequential ASCII socket to visualize
992      the local mesh, and PetscObjectView(dm,local_socket)
993      is internally called inside VecView_GLVis, incurring
994      in an error here */
995   /* PetscCheckSameComm(dm,1,v,2); */
996   PetscCall(PetscViewerCheckWritable(v));
997 
998   PetscCall(PetscLogEventBegin(DM_View, v, 0, 0, 0));
999   PetscCall(PetscViewerGetFormat(v, &format));
1000   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1001   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1002   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v));
1003   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary));
1004   if (isbinary) {
1005     PetscInt classid = DM_FILE_CLASSID;
1006     char     type[256];
1007 
1008     PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT));
1009     PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type)));
1010     PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR));
1011   }
1012   PetscTryTypeMethod(dm, view, v);
1013   PetscCall(PetscLogEventEnd(DM_View, v, 0, 0, 0));
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016 
1017 /*@
1018   DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
1019   that is it has no ghost locations.
1020 
1021   Collective
1022 
1023   Input Parameter:
1024 . dm - the `DM` object
1025 
1026   Output Parameter:
1027 . vec - the global vector
1028 
1029   Level: beginner
1030 
1031 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1032          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1033 @*/
DMCreateGlobalVector(DM dm,Vec * vec)1034 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
1035 {
1036   PetscFunctionBegin;
1037   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1038   PetscAssertPointer(vec, 2);
1039   PetscUseTypeMethod(dm, createglobalvector, vec);
1040   if (PetscDefined(USE_DEBUG)) {
1041     DM vdm;
1042 
1043     PetscCall(VecGetDM(*vec, &vdm));
1044     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1045   }
1046   PetscFunctionReturn(PETSC_SUCCESS);
1047 }
1048 
1049 /*@
1050   DMCreateLocalVector - Creates a local vector from a `DM` object.
1051 
1052   Not Collective
1053 
1054   Input Parameter:
1055 . dm - the `DM` object
1056 
1057   Output Parameter:
1058 . vec - the local vector
1059 
1060   Level: beginner
1061 
1062   Note:
1063   A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1064 
1065 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1066          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1067 @*/
DMCreateLocalVector(DM dm,Vec * vec)1068 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1069 {
1070   PetscFunctionBegin;
1071   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1072   PetscAssertPointer(vec, 2);
1073   PetscUseTypeMethod(dm, createlocalvector, vec);
1074   if (PetscDefined(USE_DEBUG)) {
1075     DM vdm;
1076 
1077     PetscCall(VecGetDM(*vec, &vdm));
1078     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1079   }
1080   PetscFunctionReturn(PETSC_SUCCESS);
1081 }
1082 
1083 /*@
1084   DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1085 
1086   Collective
1087 
1088   Input Parameter:
1089 . dm - the `DM` that provides the mapping
1090 
1091   Output Parameter:
1092 . ltog - the mapping
1093 
1094   Level: advanced
1095 
1096   Notes:
1097   The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1098 
1099   Vectors obtained with  `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1100   need to use this function with those objects.
1101 
1102   This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1103 
1104 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1105           `DMCreateMatrix()`
1106 @*/
DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping * ltog)1107 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1108 {
1109   PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1110 
1111   PetscFunctionBegin;
1112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113   PetscAssertPointer(ltog, 2);
1114   if (!dm->ltogmap) {
1115     PetscSection section, sectionGlobal;
1116 
1117     PetscCall(DMGetLocalSection(dm, &section));
1118     if (section) {
1119       const PetscInt *cdofs;
1120       PetscInt       *ltog;
1121       PetscInt        pStart, pEnd, n, p, k, l;
1122 
1123       PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1124       PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1125       PetscCall(PetscSectionGetStorageSize(section, &n));
1126       PetscCall(PetscMalloc1(n, &ltog)); /* We want the local+overlap size */
1127       for (p = pStart, l = 0; p < pEnd; ++p) {
1128         PetscInt bdof, cdof, dof, off, c, cind;
1129 
1130         /* Should probably use constrained dofs */
1131         PetscCall(PetscSectionGetDof(section, p, &dof));
1132         PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1133         PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs));
1134         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off));
1135         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1136         bdof = cdof && (dof - cdof) ? 1 : dof;
1137         if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1138 
1139         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1140           if (cind < cdof && c == cdofs[cind]) {
1141             ltog[l] = off < 0 ? off - c : -(off + c + 1);
1142             cind++;
1143           } else {
1144             ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1145           }
1146         }
1147       }
1148       /* Must have same blocksize on all procs (some might have no points) */
1149       bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
1150       bsLocal[1] = bs;
1151       PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1152       if (bsMinMax[0] != bsMinMax[1]) {
1153         bs = 1;
1154       } else {
1155         bs = bsMinMax[0];
1156       }
1157       bs = bs < 0 ? 1 : bs;
1158       /* Must reduce indices by blocksize */
1159       if (bs > 1) {
1160         for (l = 0, k = 0; l < n; l += bs, ++k) {
1161           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1162           ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1163         }
1164         n /= bs;
1165       }
1166       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap));
1167     } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1168   }
1169   *ltog = dm->ltogmap;
1170   PetscFunctionReturn(PETSC_SUCCESS);
1171 }
1172 
1173 /*@
1174   DMGetBlockSize - Gets the inherent block size associated with a `DM`
1175 
1176   Not Collective
1177 
1178   Input Parameter:
1179 . dm - the `DM` with block structure
1180 
1181   Output Parameter:
1182 . bs - the block size, 1 implies no exploitable block structure
1183 
1184   Level: intermediate
1185 
1186   Notes:
1187   This might be the number of degrees of freedom at each grid point for a structured grid.
1188 
1189   Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1190   rather different locations in the vectors may have a different block size.
1191 
1192 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1193 @*/
DMGetBlockSize(DM dm,PetscInt * bs)1194 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1195 {
1196   PetscFunctionBegin;
1197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1198   PetscAssertPointer(bs, 2);
1199   PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet");
1200   *bs = dm->bs;
1201   PetscFunctionReturn(PETSC_SUCCESS);
1202 }
1203 
1204 /*@
1205   DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1206   `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1207 
1208   Collective
1209 
1210   Input Parameters:
1211 + dmc - the `DM` object
1212 - dmf - the second, finer `DM` object
1213 
1214   Output Parameters:
1215 + mat - the interpolation
1216 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()`
1217 
1218   Level: developer
1219 
1220   Notes:
1221   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1222   DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1223 
1224   For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1225   vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1226 
1227 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1228 @*/
DMCreateInterpolation(DM dmc,DM dmf,Mat * mat,Vec * vec)1229 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1230 {
1231   PetscFunctionBegin;
1232   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1233   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1234   PetscAssertPointer(mat, 3);
1235   PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0));
1236   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1237   PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0));
1238   PetscFunctionReturn(PETSC_SUCCESS);
1239 }
1240 
1241 /*@
1242   DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is
1243   the transpose of the interpolation between the `DM`.
1244 
1245   Input Parameters:
1246 + dac - `DM` that defines a coarse mesh
1247 . daf - `DM` that defines a fine mesh
1248 - mat - the restriction (or interpolation operator) from fine to coarse
1249 
1250   Output Parameter:
1251 . scale - the scaled vector
1252 
1253   Level: advanced
1254 
1255   Note:
1256   xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual)
1257   restriction. In other words xcoarse is the coarse representation of xfine.
1258 
1259   Developer Note:
1260   If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1261   on the restriction/interpolation operator to set the bindingpropagates flag to true.
1262 
1263 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()`
1264 @*/
DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec * scale)1265 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1266 {
1267   Vec         fine;
1268   PetscScalar one = 1.0;
1269 #if defined(PETSC_HAVE_CUDA)
1270   PetscBool bindingpropagates, isbound;
1271 #endif
1272 
1273   PetscFunctionBegin;
1274   PetscCall(DMCreateGlobalVector(daf, &fine));
1275   PetscCall(DMCreateGlobalVector(dac, scale));
1276   PetscCall(VecSet(fine, one));
1277 #if defined(PETSC_HAVE_CUDA)
1278   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1279    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1280    * we'll need to do it for that case, too.*/
1281   PetscCall(VecGetBindingPropagates(fine, &bindingpropagates));
1282   if (bindingpropagates) {
1283     PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
1284     PetscCall(VecBoundToCPU(fine, &isbound));
1285     PetscCall(MatBindToCPU(mat, isbound));
1286   }
1287 #endif
1288   PetscCall(MatRestrict(mat, fine, *scale));
1289   PetscCall(VecDestroy(&fine));
1290   PetscCall(VecReciprocal(*scale));
1291   PetscFunctionReturn(PETSC_SUCCESS);
1292 }
1293 
1294 /*@
1295   DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1296   `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1297 
1298   Collective
1299 
1300   Input Parameters:
1301 + dmc - the `DM` object
1302 - dmf - the second, finer `DM` object
1303 
1304   Output Parameter:
1305 . mat - the restriction
1306 
1307   Level: developer
1308 
1309   Note:
1310   This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1311   matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1312 
1313 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1314 @*/
DMCreateRestriction(DM dmc,DM dmf,Mat * mat)1315 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1316 {
1317   PetscFunctionBegin;
1318   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1319   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1320   PetscAssertPointer(mat, 3);
1321   PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0));
1322   PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1323   PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0));
1324   PetscFunctionReturn(PETSC_SUCCESS);
1325 }
1326 
1327 /*@
1328   DMCreateInjection - Gets injection matrix between two `DM` objects.
1329 
1330   Collective
1331 
1332   Input Parameters:
1333 + dac - the `DM` object
1334 - daf - the second, finer `DM` object
1335 
1336   Output Parameter:
1337 . mat - the injection
1338 
1339   Level: developer
1340 
1341   Notes:
1342   This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the
1343   fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting
1344   the values on the coarse grid points. This compares to the operator obtained by
1345   `DMCreateRestriction()` or the transpose of the operator obtained by
1346   `DMCreateInterpolation()` that uses a "local weighted average" of the values around the
1347   coarse grid point as the coarse grid value.
1348 
1349   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1350   `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1351 
1352 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1353           `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1354 @*/
DMCreateInjection(DM dac,DM daf,Mat * mat)1355 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1356 {
1357   PetscFunctionBegin;
1358   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
1359   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
1360   PetscAssertPointer(mat, 3);
1361   PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0));
1362   PetscUseTypeMethod(dac, createinjection, daf, mat);
1363   PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0));
1364   PetscFunctionReturn(PETSC_SUCCESS);
1365 }
1366 
1367 /*@
1368   DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1369   a Galerkin finite element model on the `DM`
1370 
1371   Collective
1372 
1373   Input Parameters:
1374 + dmc - the target `DM` object
1375 - dmf - the source `DM` object, can be `NULL`
1376 
1377   Output Parameter:
1378 . mat - the mass matrix
1379 
1380   Level: developer
1381 
1382   Notes:
1383   For `DMPLEX` the finite element model for the `DM` must have been already provided.
1384 
1385   if `dmc` is `dmf` or `NULL`, then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1386 
1387 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1388 @*/
DMCreateMassMatrix(DM dmc,DM dmf,Mat * mat)1389 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1390 {
1391   PetscFunctionBegin;
1392   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1393   if (!dmf) dmf = dmc;
1394   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1395   PetscAssertPointer(mat, 3);
1396   PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1397   PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1398   PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1399   PetscFunctionReturn(PETSC_SUCCESS);
1400 }
1401 
1402 /*@
1403   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1404 
1405   Collective
1406 
1407   Input Parameter:
1408 . dm - the `DM` object
1409 
1410   Output Parameters:
1411 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector
1412 - lm  - the global lumped mass matrix, which is a diagonal matrix, represented as a vector
1413 
1414   Level: developer
1415 
1416   Note:
1417   See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1418 
1419 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1420 @*/
DMCreateMassMatrixLumped(DM dm,Vec * llm,Vec * lm)1421 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm)
1422 {
1423   PetscFunctionBegin;
1424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1425   if (llm) PetscAssertPointer(llm, 2);
1426   if (lm) PetscAssertPointer(lm, 3);
1427   if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm);
1428   PetscFunctionReturn(PETSC_SUCCESS);
1429 }
1430 
1431 /*@
1432   DMCreateGradientMatrix - Gets the gradient matrix between two `DM` objects, M_(ic)j = \int \partial_c \phi_i \psi_j where the \phi are Galerkin basis functions for a Galerkin finite element model on the `DM`
1433 
1434   Collective
1435 
1436   Input Parameters:
1437 + dmc - the target `DM` object
1438 - dmf - the source `DM` object, can be `NULL`
1439 
1440   Output Parameter:
1441 . mat - the gradient matrix
1442 
1443   Level: developer
1444 
1445   Notes:
1446   For `DMPLEX` the finite element model for the `DM` must have been already provided.
1447 
1448 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1449 @*/
DMCreateGradientMatrix(DM dmc,DM dmf,Mat * mat)1450 PetscErrorCode DMCreateGradientMatrix(DM dmc, DM dmf, Mat *mat)
1451 {
1452   PetscFunctionBegin;
1453   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1454   if (!dmf) dmf = dmc;
1455   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1456   PetscAssertPointer(mat, 3);
1457   PetscUseTypeMethod(dmc, creategradientmatrix, dmf, mat);
1458   PetscFunctionReturn(PETSC_SUCCESS);
1459 }
1460 
1461 /*@
1462   DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1463   of a PDE on the `DM`.
1464 
1465   Collective
1466 
1467   Input Parameters:
1468 + dm    - the `DM` object
1469 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1470 
1471   Output Parameter:
1472 . coloring - the coloring
1473 
1474   Level: developer
1475 
1476   Notes:
1477   Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1478   matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1479 
1480   This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1481   For `DMDA` in three dimensions with periodic boundary conditions the number of grid points in each dimension must be divisible by 2*stencil_width + 1,
1482   otherwise an error will be generated.
1483 
1484 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1485 @*/
DMCreateColoring(DM dm,ISColoringType ctype,ISColoring * coloring)1486 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1487 {
1488   PetscFunctionBegin;
1489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1490   PetscAssertPointer(coloring, 3);
1491   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1492   PetscFunctionReturn(PETSC_SUCCESS);
1493 }
1494 
1495 /*@
1496   DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1497 
1498   Collective
1499 
1500   Input Parameter:
1501 . dm - the `DM` object
1502 
1503   Output Parameter:
1504 . mat - the empty Jacobian
1505 
1506   Options Database Key:
1507 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1508 
1509   Level: beginner
1510 
1511   Notes:
1512   This properly preallocates the number of nonzeros in the sparse matrix so you
1513   do not need to do it yourself.
1514 
1515   By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1516   the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1517 
1518   For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1519   internally by PETSc.
1520 
1521   For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1522   `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1523 
1524 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1525 @*/
DMCreateMatrix(DM dm,Mat * mat)1526 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1527 {
1528   PetscFunctionBegin;
1529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1530   PetscAssertPointer(mat, 2);
1531   PetscCall(MatInitializePackage());
1532   PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0));
1533   PetscUseTypeMethod(dm, creatematrix, mat);
1534   if (PetscDefined(USE_DEBUG)) {
1535     DM mdm;
1536 
1537     PetscCall(MatGetDM(*mat, &mdm));
1538     PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name);
1539   }
1540   /* Handle nullspace and near nullspace */
1541   if (dm->Nf) {
1542     MatNullSpace nullSpace;
1543     PetscInt     Nf, f;
1544 
1545     PetscCall(DMGetNumFields(dm, &Nf));
1546     for (f = 0; f < Nf; ++f) {
1547       if (dm->nullspaceConstructors && dm->nullspaceConstructors[f]) {
1548         PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace));
1549         PetscCall(MatSetNullSpace(*mat, nullSpace));
1550         PetscCall(MatNullSpaceDestroy(&nullSpace));
1551         break;
1552       }
1553     }
1554     for (f = 0; f < Nf; ++f) {
1555       if (dm->nearnullspaceConstructors && dm->nearnullspaceConstructors[f]) {
1556         PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace));
1557         PetscCall(MatSetNearNullSpace(*mat, nullSpace));
1558         PetscCall(MatNullSpaceDestroy(&nullSpace));
1559       }
1560     }
1561   }
1562   PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0));
1563   PetscFunctionReturn(PETSC_SUCCESS);
1564 }
1565 
1566 /*@
1567   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and
1568   `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the
1569   matrices will not be preallocated.
1570 
1571   Logically Collective
1572 
1573   Input Parameters:
1574 + dm   - the `DM`
1575 - skip - `PETSC_TRUE` to skip preallocation
1576 
1577   Level: developer
1578 
1579   Note:
1580   This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and
1581   `MatSetValuesCOO()` will be used.
1582 
1583 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1584 @*/
DMSetMatrixPreallocateSkip(DM dm,PetscBool skip)1585 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1586 {
1587   PetscFunctionBegin;
1588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1589   dm->prealloc_skip = skip;
1590   PetscFunctionReturn(PETSC_SUCCESS);
1591 }
1592 
1593 /*@
1594   DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1595   preallocated but the nonzero structure and zero values will not be set.
1596 
1597   Logically Collective
1598 
1599   Input Parameters:
1600 + dm   - the `DM`
1601 - only - `PETSC_TRUE` if only want preallocation
1602 
1603   Options Database Key:
1604 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1605 
1606   Level: developer
1607 
1608 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1609 @*/
DMSetMatrixPreallocateOnly(DM dm,PetscBool only)1610 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1611 {
1612   PetscFunctionBegin;
1613   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1614   dm->prealloc_only = only;
1615   PetscFunctionReturn(PETSC_SUCCESS);
1616 }
1617 
1618 /*@
1619   DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix nonzero structure will be created
1620   but the array for numerical values will not be allocated.
1621 
1622   Logically Collective
1623 
1624   Input Parameters:
1625 + dm   - the `DM`
1626 - only - `PETSC_TRUE` if you only want matrix nonzero structure
1627 
1628   Level: developer
1629 
1630 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1631 @*/
DMSetMatrixStructureOnly(DM dm,PetscBool only)1632 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1633 {
1634   PetscFunctionBegin;
1635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1636   dm->structure_only = only;
1637   PetscFunctionReturn(PETSC_SUCCESS);
1638 }
1639 
1640 /*@
1641   DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1642 
1643   Logically Collective
1644 
1645   Input Parameters:
1646 + dm    - the `DM`
1647 - btype - block by topological point or field node
1648 
1649   Options Database Key:
1650 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking
1651 
1652   Level: advanced
1653 
1654 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1655 @*/
DMSetBlockingType(DM dm,DMBlockingType btype)1656 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype)
1657 {
1658   PetscFunctionBegin;
1659   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1660   dm->blocking_type = btype;
1661   PetscFunctionReturn(PETSC_SUCCESS);
1662 }
1663 
1664 /*@
1665   DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1666 
1667   Not Collective
1668 
1669   Input Parameter:
1670 . dm - the `DM`
1671 
1672   Output Parameter:
1673 . btype - block by topological point or field node
1674 
1675   Level: advanced
1676 
1677 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1678 @*/
DMGetBlockingType(DM dm,DMBlockingType * btype)1679 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype)
1680 {
1681   PetscFunctionBegin;
1682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1683   PetscAssertPointer(btype, 2);
1684   *btype = dm->blocking_type;
1685   PetscFunctionReturn(PETSC_SUCCESS);
1686 }
1687 
1688 /*@C
1689   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1690 
1691   Not Collective
1692 
1693   Input Parameters:
1694 + dm    - the `DM` object
1695 . count - The minimum size
1696 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`)
1697 
1698   Output Parameter:
1699 . mem - the work array
1700 
1701   Level: developer
1702 
1703   Notes:
1704   A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1705 
1706   The array may contain nonzero values
1707 
1708 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1709 @*/
DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void * mem)1710 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1711 {
1712   DMWorkLink  link;
1713   PetscMPIInt dsize;
1714 
1715   PetscFunctionBegin;
1716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1717   PetscAssertPointer(mem, 4);
1718   if (!count) {
1719     *(void **)mem = NULL;
1720     PetscFunctionReturn(PETSC_SUCCESS);
1721   }
1722   if (dm->workin) {
1723     link       = dm->workin;
1724     dm->workin = dm->workin->next;
1725   } else {
1726     PetscCall(PetscNew(&link));
1727   }
1728   /* Avoid MPI_Type_size for most used datatypes
1729      Get size directly */
1730   if (dtype == MPIU_INT) dsize = sizeof(PetscInt);
1731   else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal);
1732 #if defined(PETSC_USE_64BIT_INDICES)
1733   else if (dtype == MPI_INT) dsize = sizeof(int);
1734 #endif
1735 #if defined(PETSC_USE_COMPLEX)
1736   else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar);
1737 #endif
1738   else PetscCallMPI(MPI_Type_size(dtype, &dsize));
1739 
1740   if (((size_t)dsize * count) > link->bytes) {
1741     PetscCall(PetscFree(link->mem));
1742     PetscCall(PetscMalloc(dsize * count, &link->mem));
1743     link->bytes = dsize * count;
1744   }
1745   link->next    = dm->workout;
1746   dm->workout   = link;
1747   *(void **)mem = link->mem;
1748   PetscFunctionReturn(PETSC_SUCCESS);
1749 }
1750 
1751 /*@C
1752   DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1753 
1754   Not Collective
1755 
1756   Input Parameters:
1757 + dm    - the `DM` object
1758 . count - The minimum size
1759 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT`
1760 
1761   Output Parameter:
1762 . mem - the work array
1763 
1764   Level: developer
1765 
1766   Developer Note:
1767   count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1768 
1769 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1770 @*/
DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void * mem)1771 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1772 {
1773   DMWorkLink *p, link;
1774 
1775   PetscFunctionBegin;
1776   PetscAssertPointer(mem, 4);
1777   (void)count;
1778   (void)dtype;
1779   if (!*(void **)mem) PetscFunctionReturn(PETSC_SUCCESS);
1780   for (p = &dm->workout; (link = *p); p = &link->next) {
1781     if (link->mem == *(void **)mem) {
1782       *p            = link->next;
1783       link->next    = dm->workin;
1784       dm->workin    = link;
1785       *(void **)mem = NULL;
1786       PetscFunctionReturn(PETSC_SUCCESS);
1787     }
1788   }
1789   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1790 }
1791 
1792 /*@C
1793   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1794   are joined or split, such as in `DMCreateSubDM()`
1795 
1796   Logically Collective; No Fortran Support
1797 
1798   Input Parameters:
1799 + dm     - The `DM`
1800 . field  - The field number for the nullspace
1801 - nullsp - A callback to create the nullspace
1802 
1803   Calling sequence of `nullsp`:
1804 + dm        - The present `DM`
1805 . origField - The field number given above, in the original `DM`
1806 . field     - The field number in dm
1807 - nullSpace - The nullspace for the given field
1808 
1809   Level: intermediate
1810 
1811 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1812 @*/
DMSetNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (* nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1813 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1814 {
1815   PetscFunctionBegin;
1816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1817   PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1818   PetscCheck(dm->nullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1819   dm->nullspaceConstructors[field] = nullsp;
1820   PetscFunctionReturn(PETSC_SUCCESS);
1821 }
1822 
1823 /*@C
1824   DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`
1825 
1826   Not Collective; No Fortran Support
1827 
1828   Input Parameters:
1829 + dm    - The `DM`
1830 - field - The field number for the nullspace
1831 
1832   Output Parameter:
1833 . nullsp - A callback to create the nullspace
1834 
1835   Calling sequence of `nullsp`:
1836 + dm        - The present DM
1837 . origField - The field number given above, in the original DM
1838 . field     - The field number in dm
1839 - nullSpace - The nullspace for the given field
1840 
1841   Level: intermediate
1842 
1843 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1844 @*/
DMGetNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (** nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1845 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1846 {
1847   PetscFunctionBegin;
1848   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1849   PetscAssertPointer(nullsp, 3);
1850   PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1851   PetscCheck(dm->nullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1852   *nullsp = dm->nullspaceConstructors[field];
1853   PetscFunctionReturn(PETSC_SUCCESS);
1854 }
1855 
1856 /*@C
1857   DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1858 
1859   Logically Collective; No Fortran Support
1860 
1861   Input Parameters:
1862 + dm     - The `DM`
1863 . field  - The field number for the nullspace
1864 - nullsp - A callback to create the near-nullspace
1865 
1866   Calling sequence of `nullsp`:
1867 + dm        - The present `DM`
1868 . origField - The field number given above, in the original `DM`
1869 . field     - The field number in dm
1870 - nullSpace - The nullspace for the given field
1871 
1872   Level: intermediate
1873 
1874 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1875           `MatNullSpace`
1876 @*/
DMSetNearNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (* nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1877 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1878 {
1879   PetscFunctionBegin;
1880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1881   PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1882   PetscCheck(dm->nearnullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1883   dm->nearnullspaceConstructors[field] = nullsp;
1884   PetscFunctionReturn(PETSC_SUCCESS);
1885 }
1886 
1887 /*@C
1888   DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1889 
1890   Not Collective; No Fortran Support
1891 
1892   Input Parameters:
1893 + dm    - The `DM`
1894 - field - The field number for the nullspace
1895 
1896   Output Parameter:
1897 . nullsp - A callback to create the near-nullspace
1898 
1899   Calling sequence of `nullsp`:
1900 + dm        - The present `DM`
1901 . origField - The field number given above, in the original `DM`
1902 . field     - The field number in dm
1903 - nullSpace - The nullspace for the given field
1904 
1905   Level: intermediate
1906 
1907 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1908           `MatNullSpace`, `DMCreateSuperDM()`
1909 @*/
DMGetNearNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (** nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1910 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1911 {
1912   PetscFunctionBegin;
1913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1914   PetscAssertPointer(nullsp, 3);
1915   PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1916   PetscCheck(dm->nearnullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1917   *nullsp = dm->nearnullspaceConstructors[field];
1918   PetscFunctionReturn(PETSC_SUCCESS);
1919 }
1920 
1921 /*@C
1922   DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`
1923 
1924   Not Collective; No Fortran Support
1925 
1926   Input Parameter:
1927 . dm - the `DM` object
1928 
1929   Output Parameters:
1930 + numFields  - The number of fields (or `NULL` if not requested)
1931 . fieldNames - The name of each field (or `NULL` if not requested)
1932 - fields     - The global indices for each field (or `NULL` if not requested)
1933 
1934   Level: intermediate
1935 
1936   Note:
1937   The user is responsible for freeing all requested arrays. In particular, every entry of `fieldNames` should be freed with
1938   `PetscFree()`, every entry of `fields` should be destroyed with `ISDestroy()`, and both arrays should be freed with
1939   `PetscFree()`.
1940 
1941   Developer Note:
1942   It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1943   likely be removed.
1944 
1945 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1946           `DMCreateFieldDecomposition()`
1947 @*/
DMCreateFieldIS(DM dm,PetscInt * numFields,char *** fieldNames,IS * fields[])1948 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS *fields[])
1949 {
1950   PetscSection section, sectionGlobal;
1951 
1952   PetscFunctionBegin;
1953   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1954   if (numFields) {
1955     PetscAssertPointer(numFields, 2);
1956     *numFields = 0;
1957   }
1958   if (fieldNames) {
1959     PetscAssertPointer(fieldNames, 3);
1960     *fieldNames = NULL;
1961   }
1962   if (fields) {
1963     PetscAssertPointer(fields, 4);
1964     *fields = NULL;
1965   }
1966   PetscCall(DMGetLocalSection(dm, &section));
1967   if (section) {
1968     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1969     PetscInt  nF, f, pStart, pEnd, p;
1970 
1971     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1972     PetscCall(PetscSectionGetNumFields(section, &nF));
1973     PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices));
1974     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
1975     for (f = 0; f < nF; ++f) {
1976       fieldSizes[f] = 0;
1977       PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f]));
1978     }
1979     for (p = pStart; p < pEnd; ++p) {
1980       PetscInt gdof;
1981 
1982       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1983       if (gdof > 0) {
1984         for (f = 0; f < nF; ++f) {
1985           PetscInt fdof, fcdof, fpdof;
1986 
1987           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1988           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1989           fpdof = fdof - fcdof;
1990           if (fpdof && fpdof != fieldNc[f]) {
1991             /* Layout does not admit a pointwise block size */
1992             fieldNc[f] = 1;
1993           }
1994           fieldSizes[f] += fpdof;
1995         }
1996       }
1997     }
1998     for (f = 0; f < nF; ++f) {
1999       PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f]));
2000       fieldSizes[f] = 0;
2001     }
2002     for (p = pStart; p < pEnd; ++p) {
2003       PetscInt gdof, goff;
2004 
2005       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
2006       if (gdof > 0) {
2007         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
2008         for (f = 0; f < nF; ++f) {
2009           PetscInt fdof, fcdof, fc;
2010 
2011           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
2012           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
2013           for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
2014         }
2015       }
2016     }
2017     if (numFields) *numFields = nF;
2018     if (fieldNames) {
2019       PetscCall(PetscMalloc1(nF, fieldNames));
2020       for (f = 0; f < nF; ++f) {
2021         const char *fieldName;
2022 
2023         PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2024         PetscCall(PetscStrallocpy(fieldName, &(*fieldNames)[f]));
2025       }
2026     }
2027     if (fields) {
2028       PetscCall(PetscMalloc1(nF, fields));
2029       for (f = 0; f < nF; ++f) {
2030         PetscInt bs, in[2], out[2];
2031 
2032         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]));
2033         in[0] = -fieldNc[f];
2034         in[1] = fieldNc[f];
2035         PetscCallMPI(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
2036         bs = (-out[0] == out[1]) ? out[1] : 1;
2037         PetscCall(ISSetBlockSize((*fields)[f], bs));
2038       }
2039     }
2040     PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices));
2041   } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
2042   PetscFunctionReturn(PETSC_SUCCESS);
2043 }
2044 
2045 /*@C
2046   DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
2047   corresponding to different fields.
2048 
2049   Not Collective; No Fortran Support
2050 
2051   Input Parameter:
2052 . dm - the `DM` object
2053 
2054   Output Parameters:
2055 + len      - The number of fields (or `NULL` if not requested)
2056 . namelist - The name for each field (or `NULL` if not requested)
2057 . islist   - The global indices for each field (or `NULL` if not requested)
2058 - dmlist   - The `DM`s for each field subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2059 
2060   Level: intermediate
2061 
2062   Notes:
2063   Each `IS` contains the global indices of the dofs of the corresponding field, defined by
2064   `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
2065 
2066   The same as `DMCreateFieldIS()` but also returns a `DM` for each field.
2067 
2068   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2069   `PetscFree()`, every entry of `islist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2070   and all of the arrays should be freed with `PetscFree()`.
2071 
2072   Fortran Notes:
2073   Use the declarations
2074 .vb
2075   character(80), pointer :: namelist(:)
2076   IS, pointer :: islist(:)
2077   DM, pointer :: dmlist(:)
2078 .ve
2079 
2080   `namelist` must be provided, `islist` may be `PETSC_NULL_IS_POINTER` and `dmlist` may be `PETSC_NULL_DM_POINTER`
2081 
2082   Use `DMDestroyFieldDecomposition()` to free the returned objects
2083 
2084   Developer Notes:
2085   It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.
2086 
2087   Unlike  `DMRefine()`, `DMCoarsen()`, and `DMCreateDomainDecomposition()` this provides no mechanism to provide hooks that are called after the
2088   decomposition is computed.
2089 
2090 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2091 @*/
DMCreateFieldDecomposition(DM dm,PetscInt * len,char *** namelist,IS * islist[],DM * dmlist[])2092 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS *islist[], DM *dmlist[])
2093 {
2094   PetscFunctionBegin;
2095   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2096   if (len) {
2097     PetscAssertPointer(len, 2);
2098     *len = 0;
2099   }
2100   if (namelist) {
2101     PetscAssertPointer(namelist, 3);
2102     *namelist = NULL;
2103   }
2104   if (islist) {
2105     PetscAssertPointer(islist, 4);
2106     *islist = NULL;
2107   }
2108   if (dmlist) {
2109     PetscAssertPointer(dmlist, 5);
2110     *dmlist = NULL;
2111   }
2112   /*
2113    Is it a good idea to apply the following check across all impls?
2114    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2115    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2116    */
2117   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2118   if (!dm->ops->createfielddecomposition) {
2119     PetscSection section;
2120     PetscInt     numFields, f;
2121 
2122     PetscCall(DMGetLocalSection(dm, &section));
2123     if (section) PetscCall(PetscSectionGetNumFields(section, &numFields));
2124     if (section && numFields && dm->ops->createsubdm) {
2125       if (len) *len = numFields;
2126       if (namelist) PetscCall(PetscMalloc1(numFields, namelist));
2127       if (islist) PetscCall(PetscMalloc1(numFields, islist));
2128       if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist));
2129       for (f = 0; f < numFields; ++f) {
2130         const char *fieldName;
2131 
2132         PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL));
2133         if (namelist) {
2134           PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2135           PetscCall(PetscStrallocpy(fieldName, &(*namelist)[f]));
2136         }
2137       }
2138     } else {
2139       PetscCall(DMCreateFieldIS(dm, len, namelist, islist));
2140       /* By default there are no DMs associated with subproblems. */
2141       if (dmlist) *dmlist = NULL;
2142     }
2143   } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
2144   PetscFunctionReturn(PETSC_SUCCESS);
2145 }
2146 
2147 /*@
2148   DMCreateSubDM - Returns an `IS` and `DM` encapsulating a subproblem defined by the fields passed in.
2149   The fields are defined by `DMCreateFieldIS()`.
2150 
2151   Not collective
2152 
2153   Input Parameters:
2154 + dm        - The `DM` object
2155 . numFields - The number of fields to select
2156 - fields    - The field numbers of the selected fields
2157 
2158   Output Parameters:
2159 + is    - The global indices for all the degrees of freedom in the new sub `DM`, use `NULL` if not needed
2160 - subdm - The `DM` for the subproblem, use `NULL` if not needed
2161 
2162   Level: intermediate
2163 
2164   Note:
2165   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2166 
2167 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `IS`, `VecISCopy()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
2168 @*/
DMCreateSubDM(DM dm,PetscInt numFields,const PetscInt fields[],IS * is,DM * subdm)2169 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2170 {
2171   PetscFunctionBegin;
2172   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2173   PetscAssertPointer(fields, 3);
2174   if (is) PetscAssertPointer(is, 4);
2175   if (subdm) PetscAssertPointer(subdm, 5);
2176   PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2177   PetscFunctionReturn(PETSC_SUCCESS);
2178 }
2179 
2180 /*@C
2181   DMCreateSuperDM - Returns an arrays of `IS` and a single `DM` encapsulating a superproblem defined by multiple `DM`s passed in.
2182 
2183   Not collective
2184 
2185   Input Parameters:
2186 + dms - The `DM` objects
2187 - n   - The number of `DM`s
2188 
2189   Output Parameters:
2190 + is      - The global indices for each of subproblem within the super `DM`, or `NULL`, its length is `n`
2191 - superdm - The `DM` for the superproblem
2192 
2193   Level: intermediate
2194 
2195   Note:
2196   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2197 
2198 .seealso: [](ch_dmbase), `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`, `DMCreateDomainDecomposition()`
2199 @*/
DMCreateSuperDM(DM dms[],PetscInt n,IS * is[],DM * superdm)2200 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS *is[], DM *superdm)
2201 {
2202   PetscInt i;
2203 
2204   PetscFunctionBegin;
2205   PetscAssertPointer(dms, 1);
2206   for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1);
2207   if (is) PetscAssertPointer(is, 3);
2208   PetscAssertPointer(superdm, 4);
2209   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n);
2210   if (n) {
2211     DM dm = dms[0];
2212     PetscCheck(dm->ops->createsuperdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No method createsuperdm for DM of type %s", ((PetscObject)dm)->type_name);
2213     PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm));
2214   }
2215   PetscFunctionReturn(PETSC_SUCCESS);
2216 }
2217 
2218 /*@C
2219   DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a
2220   problem into subproblems corresponding to restrictions to pairs of nested subdomains.
2221 
2222   Not Collective
2223 
2224   Input Parameter:
2225 . dm - the `DM` object
2226 
2227   Output Parameters:
2228 + n           - The number of subproblems in the domain decomposition (or `NULL` if not requested), also the length of the four arrays below
2229 . namelist    - The name for each subdomain (or `NULL` if not requested)
2230 . innerislist - The global indices for each inner subdomain (or `NULL`, if not requested)
2231 . outerislist - The global indices for each outer subdomain (or `NULL`, if not requested)
2232 - dmlist      - The `DM`s for each subdomain subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2233 
2234   Level: intermediate
2235 
2236   Notes:
2237   Each `IS` contains the global indices of the dofs of the corresponding subdomains with in the
2238   dofs of the original `DM`. The inner subdomains conceptually define a nonoverlapping
2239   covering, while outer subdomains can overlap.
2240 
2241   The optional list of `DM`s define a `DM` for each subproblem.
2242 
2243   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2244   `PetscFree()`, every entry of `innerislist` and `outerislist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2245   and all of the arrays should be freed with `PetscFree()`.
2246 
2247   Developer Notes:
2248   The `dmlist` is for the inner subdomains or the outer subdomains or all subdomains?
2249 
2250   The names are inconsistent, the hooks use `DMSubDomainHook` which is nothing like `DMCreateDomainDecomposition()` while `DMRefineHook` is used for `DMRefine()`.
2251 
2252 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`,
2253           `DMSubDomainHookAdd()`, `DMSubDomainHookRemove()`,`DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2254 @*/
DMCreateDomainDecomposition(DM dm,PetscInt * n,char *** namelist,IS * innerislist[],IS * outerislist[],DM * dmlist[])2255 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS *innerislist[], IS *outerislist[], DM *dmlist[])
2256 {
2257   DMSubDomainHookLink link;
2258   PetscInt            i, l;
2259 
2260   PetscFunctionBegin;
2261   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2262   if (n) {
2263     PetscAssertPointer(n, 2);
2264     *n = 0;
2265   }
2266   if (namelist) {
2267     PetscAssertPointer(namelist, 3);
2268     *namelist = NULL;
2269   }
2270   if (innerislist) {
2271     PetscAssertPointer(innerislist, 4);
2272     *innerislist = NULL;
2273   }
2274   if (outerislist) {
2275     PetscAssertPointer(outerislist, 5);
2276     *outerislist = NULL;
2277   }
2278   if (dmlist) {
2279     PetscAssertPointer(dmlist, 6);
2280     *dmlist = NULL;
2281   }
2282   /*
2283    Is it a good idea to apply the following check across all impls?
2284    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2285    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2286    */
2287   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2288   if (dm->ops->createdomaindecomposition) {
2289     PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2290     /* copy subdomain hooks and context over to the subdomain DMs */
2291     if (dmlist && *dmlist) {
2292       for (i = 0; i < l; i++) {
2293         for (link = dm->subdomainhook; link; link = link->next) {
2294           if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx));
2295         }
2296         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2297       }
2298     }
2299     if (n) *n = l;
2300   }
2301   PetscFunctionReturn(PETSC_SUCCESS);
2302 }
2303 
2304 /*@C
2305   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector for subdomains created with
2306   `DMCreateDomainDecomposition()`
2307 
2308   Not Collective
2309 
2310   Input Parameters:
2311 + dm     - the `DM` object
2312 . n      - the number of subdomains
2313 - subdms - the local subdomains
2314 
2315   Output Parameters:
2316 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2317 . oscat - scatter from global vector to overlapping global vector entries on subdomain
2318 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2319 
2320   Level: developer
2321 
2322   Note:
2323   This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2324   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
2325   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2326   solution and residual data.
2327 
2328   Developer Note:
2329   Can the subdms input be anything or are they exactly the `DM` obtained from
2330   `DMCreateDomainDecomposition()`?
2331 
2332 .seealso: [](ch_dmbase), `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2333 @*/
DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM * subdms,VecScatter * iscat[],VecScatter * oscat[],VecScatter * gscat[])2334 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter *iscat[], VecScatter *oscat[], VecScatter *gscat[])
2335 {
2336   PetscFunctionBegin;
2337   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2338   PetscAssertPointer(subdms, 3);
2339   PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2340   PetscFunctionReturn(PETSC_SUCCESS);
2341 }
2342 
2343 /*@
2344   DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh
2345 
2346   Collective
2347 
2348   Input Parameters:
2349 + dm   - the `DM` object
2350 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
2351 
2352   Output Parameter:
2353 . dmf - the refined `DM`, or `NULL`
2354 
2355   Options Database Key:
2356 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2357 
2358   Level: developer
2359 
2360   Note:
2361   If no refinement was done, the return value is `NULL`
2362 
2363 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
2364           `DMRefineHookAdd()`, `DMRefineHookRemove()`
2365 @*/
DMRefine(DM dm,MPI_Comm comm,DM * dmf)2366 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2367 {
2368   DMRefineHookLink link;
2369 
2370   PetscFunctionBegin;
2371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2372   PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0));
2373   PetscUseTypeMethod(dm, refine, comm, dmf);
2374   if (*dmf) {
2375     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2376 
2377     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf));
2378 
2379     (*dmf)->ctx       = dm->ctx;
2380     (*dmf)->leveldown = dm->leveldown;
2381     (*dmf)->levelup   = dm->levelup + 1;
2382 
2383     PetscCall(DMSetMatType(*dmf, dm->mattype));
2384     for (link = dm->refinehook; link; link = link->next) {
2385       if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx));
2386     }
2387   }
2388   PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0));
2389   PetscFunctionReturn(PETSC_SUCCESS);
2390 }
2391 
2392 /*@C
2393   DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2394 
2395   Logically Collective; No Fortran Support
2396 
2397   Input Parameters:
2398 + coarse     - `DM` on which to run a hook when interpolating to a finer level
2399 . refinehook - function to run when setting up the finer level
2400 . interphook - function to run to update data on finer levels (once per `SNESSolve()`)
2401 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2402 
2403   Calling sequence of `refinehook`:
2404 + coarse - coarse level `DM`
2405 . fine   - fine level `DM` to interpolate problem to
2406 - ctx    - optional user-defined function context
2407 
2408   Calling sequence of `interphook`:
2409 + coarse - coarse level `DM`
2410 . interp - matrix interpolating a coarse-level solution to the finer grid
2411 . fine   - fine level `DM` to update
2412 - ctx    - optional user-defined function context
2413 
2414   Level: advanced
2415 
2416   Notes:
2417   This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2418   passed to fine grids while grid sequencing.
2419 
2420   The actual interpolation is done when `DMInterpolate()` is called.
2421 
2422   If this function is called multiple times, the hooks will be run in the order they are added.
2423 
2424 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2425 @*/
DMRefineHookAdd(DM coarse,PetscErrorCode (* refinehook)(DM coarse,DM fine,PetscCtx ctx),PetscErrorCode (* interphook)(DM coarse,Mat interp,DM fine,PetscCtx ctx),PetscCtx ctx)2426 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM coarse, DM fine, PetscCtx ctx), PetscErrorCode (*interphook)(DM coarse, Mat interp, DM fine, PetscCtx ctx), PetscCtx ctx)
2427 {
2428   DMRefineHookLink link, *p;
2429 
2430   PetscFunctionBegin;
2431   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2432   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2433     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
2434   }
2435   PetscCall(PetscNew(&link));
2436   link->refinehook = refinehook;
2437   link->interphook = interphook;
2438   link->ctx        = ctx;
2439   link->next       = NULL;
2440   *p               = link;
2441   PetscFunctionReturn(PETSC_SUCCESS);
2442 }
2443 
2444 /*@C
2445   DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2446   a nonlinear problem to a finer grid
2447 
2448   Logically Collective; No Fortran Support
2449 
2450   Input Parameters:
2451 + coarse     - the `DM` on which to run a hook when restricting to a coarser level
2452 . refinehook - function to run when setting up a finer level
2453 . interphook - function to run to update data on finer levels
2454 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2455 
2456   Level: advanced
2457 
2458   Note:
2459   This function does nothing if the hook is not in the list.
2460 
2461 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2462 @*/
DMRefineHookRemove(DM coarse,PetscErrorCode (* refinehook)(DM,DM,void *),PetscErrorCode (* interphook)(DM,Mat,DM,void *),PetscCtx ctx)2463 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), PetscCtx ctx)
2464 {
2465   DMRefineHookLink link, *p;
2466 
2467   PetscFunctionBegin;
2468   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2469   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2470     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2471       link = *p;
2472       *p   = link->next;
2473       PetscCall(PetscFree(link));
2474       break;
2475     }
2476   }
2477   PetscFunctionReturn(PETSC_SUCCESS);
2478 }
2479 
2480 /*@
2481   DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`
2482 
2483   Collective if any hooks are
2484 
2485   Input Parameters:
2486 + coarse - coarser `DM` to use as a base
2487 . interp - interpolation matrix, apply using `MatInterpolate()`
2488 - fine   - finer `DM` to update
2489 
2490   Level: developer
2491 
2492   Developer Note:
2493   This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2494   an API with consistent terminology.
2495 
2496 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2497 @*/
DMInterpolate(DM coarse,Mat interp,DM fine)2498 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2499 {
2500   DMRefineHookLink link;
2501 
2502   PetscFunctionBegin;
2503   for (link = fine->refinehook; link; link = link->next) {
2504     if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx));
2505   }
2506   PetscFunctionReturn(PETSC_SUCCESS);
2507 }
2508 
2509 /*@
2510   DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2511 
2512   Collective
2513 
2514   Input Parameters:
2515 + coarse    - coarse `DM`
2516 . fine      - fine `DM`
2517 . interp    - (optional) the matrix computed by `DMCreateInterpolation()`.  Implementations may not need this, but if it
2518             is available it can avoid some recomputation.  If it is provided, `MatInterpolate()` will be used if
2519             the coarse `DM` does not have a specialized implementation.
2520 - coarseSol - solution on the coarse mesh
2521 
2522   Output Parameter:
2523 . fineSol - the interpolation of coarseSol to the fine mesh
2524 
2525   Level: developer
2526 
2527   Note:
2528   This function exists because the interpolation of a solution vector between meshes is not always a linear
2529   map.  For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2530   out of the solution vector.  Or if interpolation is inherently a nonlinear operation, such as a method using
2531   slope-limiting reconstruction.
2532 
2533   Developer Note:
2534   This doesn't just interpolate "solutions" so its API name is questionable.
2535 
2536 .seealso: [](ch_dmbase), `DM`, `DMInterpolate()`, `DMCreateInterpolation()`
2537 @*/
DMInterpolateSolution(DM coarse,DM fine,Mat interp,Vec coarseSol,Vec fineSol)2538 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2539 {
2540   PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;
2541 
2542   PetscFunctionBegin;
2543   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2544   if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3);
2545   PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4);
2546   PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5);
2547 
2548   PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol));
2549   if (interpsol) {
2550     PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol));
2551   } else if (interp) {
2552     PetscCall(MatInterpolate(interp, coarseSol, fineSol));
2553   } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2554   PetscFunctionReturn(PETSC_SUCCESS);
2555 }
2556 
2557 /*@
2558   DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.
2559 
2560   Not Collective
2561 
2562   Input Parameter:
2563 . dm - the `DM` object
2564 
2565   Output Parameter:
2566 . level - number of refinements
2567 
2568   Level: developer
2569 
2570   Note:
2571   This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.
2572 
2573 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2574 @*/
DMGetRefineLevel(DM dm,PetscInt * level)2575 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2576 {
2577   PetscFunctionBegin;
2578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2579   *level = dm->levelup;
2580   PetscFunctionReturn(PETSC_SUCCESS);
2581 }
2582 
2583 /*@
2584   DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.
2585 
2586   Not Collective
2587 
2588   Input Parameters:
2589 + dm    - the `DM` object
2590 - level - number of refinements
2591 
2592   Level: advanced
2593 
2594   Notes:
2595   This value is used by `PCMG` to determine how many multigrid levels to use
2596 
2597   The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.
2598 
2599 .seealso: [](ch_dmbase), `DM`, `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2600 @*/
DMSetRefineLevel(DM dm,PetscInt level)2601 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2602 {
2603   PetscFunctionBegin;
2604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2605   dm->levelup = level;
2606   PetscFunctionReturn(PETSC_SUCCESS);
2607 }
2608 
2609 /*@
2610   DMExtrude - Extrude a `DM` object from a surface
2611 
2612   Collective
2613 
2614   Input Parameters:
2615 + dm     - the `DM` object
2616 - layers - the number of extruded cell layers
2617 
2618   Output Parameter:
2619 . dme - the extruded `DM`, or `NULL`
2620 
2621   Level: developer
2622 
2623   Note:
2624   If no extrusion was done, the return value is `NULL`
2625 
2626 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2627 @*/
DMExtrude(DM dm,PetscInt layers,DM * dme)2628 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2629 {
2630   PetscFunctionBegin;
2631   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2632   PetscUseTypeMethod(dm, extrude, layers, dme);
2633   if (*dme) {
2634     (*dme)->ops->creatematrix = dm->ops->creatematrix;
2635     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme));
2636     (*dme)->ctx = dm->ctx;
2637     PetscCall(DMSetMatType(*dme, dm->mattype));
2638   }
2639   PetscFunctionReturn(PETSC_SUCCESS);
2640 }
2641 
DMGetBasisTransformDM_Internal(DM dm,DM * tdm)2642 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2643 {
2644   PetscFunctionBegin;
2645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2646   PetscAssertPointer(tdm, 2);
2647   *tdm = dm->transformDM;
2648   PetscFunctionReturn(PETSC_SUCCESS);
2649 }
2650 
DMGetBasisTransformVec_Internal(DM dm,Vec * tv)2651 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2652 {
2653   PetscFunctionBegin;
2654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2655   PetscAssertPointer(tv, 2);
2656   *tv = dm->transform;
2657   PetscFunctionReturn(PETSC_SUCCESS);
2658 }
2659 
2660 /*@
2661   DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors
2662 
2663   Input Parameter:
2664 . dm - The `DM`
2665 
2666   Output Parameter:
2667 . flg - `PETSC_TRUE` if a basis transformation should be done
2668 
2669   Level: developer
2670 
2671 .seealso: [](ch_dmbase), `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2672 @*/
DMHasBasisTransform(DM dm,PetscBool * flg)2673 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2674 {
2675   Vec tv;
2676 
2677   PetscFunctionBegin;
2678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2679   PetscAssertPointer(flg, 2);
2680   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
2681   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2682   PetscFunctionReturn(PETSC_SUCCESS);
2683 }
2684 
DMConstructBasisTransform_Internal(DM dm)2685 PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2686 {
2687   PetscSection s, ts;
2688   PetscScalar *ta;
2689   PetscInt     cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2690 
2691   PetscFunctionBegin;
2692   PetscCall(DMGetCoordinateDim(dm, &cdim));
2693   PetscCall(DMGetLocalSection(dm, &s));
2694   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2695   PetscCall(PetscSectionGetNumFields(s, &Nf));
2696   PetscCall(DMClone(dm, &dm->transformDM));
2697   PetscCall(DMGetLocalSection(dm->transformDM, &ts));
2698   PetscCall(PetscSectionSetNumFields(ts, Nf));
2699   PetscCall(PetscSectionSetChart(ts, pStart, pEnd));
2700   for (f = 0; f < Nf; ++f) {
2701     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2702     /* We could start to label fields by their transformation properties */
2703     if (Nc != cdim) continue;
2704     for (p = pStart; p < pEnd; ++p) {
2705       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2706       if (!dof) continue;
2707       PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim)));
2708       PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim)));
2709     }
2710   }
2711   PetscCall(PetscSectionSetUp(ts));
2712   PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform));
2713   PetscCall(VecGetArray(dm->transform, &ta));
2714   for (p = pStart; p < pEnd; ++p) {
2715     for (f = 0; f < Nf; ++f) {
2716       PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
2717       if (dof) {
2718         PetscReal          x[3] = {0.0, 0.0, 0.0};
2719         PetscScalar       *tva;
2720         const PetscScalar *A;
2721 
2722         /* TODO Get quadrature point for this dual basis vector for coordinate */
2723         PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx));
2724         PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva));
2725         PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim)));
2726       }
2727     }
2728   }
2729   PetscCall(VecRestoreArray(dm->transform, &ta));
2730   PetscFunctionReturn(PETSC_SUCCESS);
2731 }
2732 
DMCopyTransform(DM dm,DM newdm)2733 PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2734 {
2735   PetscFunctionBegin;
2736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2737   PetscValidHeaderSpecific(newdm, DM_CLASSID, 2);
2738   newdm->transformCtx       = dm->transformCtx;
2739   newdm->transformSetUp     = dm->transformSetUp;
2740   newdm->transformDestroy   = NULL;
2741   newdm->transformGetMatrix = dm->transformGetMatrix;
2742   if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm));
2743   PetscFunctionReturn(PETSC_SUCCESS);
2744 }
2745 
2746 /*@C
2747   DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called
2748 
2749   Logically Collective
2750 
2751   Input Parameters:
2752 + dm        - the `DM`
2753 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2754 . endhook   - function to run after `DMGlobalToLocalEnd()` has completed
2755 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2756 
2757   Calling sequence of `beginhook`:
2758 + dm   - global `DM`
2759 . g    - global vector
2760 . mode - mode
2761 . l    - local vector
2762 - ctx  - optional user-defined function context
2763 
2764   Calling sequence of `endhook`:
2765 + dm   - global `DM`
2766 . g    - global vector
2767 . mode - mode
2768 . l    - local vector
2769 - ctx  - optional user-defined function context
2770 
2771   Level: advanced
2772 
2773   Note:
2774   The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.
2775 
2776 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2777 @*/
DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (* beginhook)(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx),PetscErrorCode (* endhook)(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx),PetscCtx ctx)2778 PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx), PetscErrorCode (*endhook)(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx), PetscCtx ctx)
2779 {
2780   DMGlobalToLocalHookLink link, *p;
2781 
2782   PetscFunctionBegin;
2783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2784   for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2785   PetscCall(PetscNew(&link));
2786   link->beginhook = beginhook;
2787   link->endhook   = endhook;
2788   link->ctx       = ctx;
2789   link->next      = NULL;
2790   *p              = link;
2791   PetscFunctionReturn(PETSC_SUCCESS);
2792 }
2793 
DMGlobalToLocalHook_Constraints(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx)2794 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx)
2795 {
2796   Mat          cMat;
2797   Vec          cVec, cBias;
2798   PetscSection section, cSec;
2799   PetscInt     pStart, pEnd, p, dof;
2800 
2801   PetscFunctionBegin;
2802   (void)g;
2803   (void)ctx;
2804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2805   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias));
2806   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2807     PetscInt nRows;
2808 
2809     PetscCall(MatGetSize(cMat, &nRows, NULL));
2810     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2811     PetscCall(DMGetLocalSection(dm, &section));
2812     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2813     PetscCall(MatMult(cMat, l, cVec));
2814     if (cBias) PetscCall(VecAXPY(cVec, 1., cBias));
2815     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2816     for (p = pStart; p < pEnd; p++) {
2817       PetscCall(PetscSectionGetDof(cSec, p, &dof));
2818       if (dof) {
2819         PetscScalar *vals;
2820         PetscCall(VecGetValuesSection(cVec, cSec, p, &vals));
2821         PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES));
2822       }
2823     }
2824     PetscCall(VecDestroy(&cVec));
2825   }
2826   PetscFunctionReturn(PETSC_SUCCESS);
2827 }
2828 
2829 /*@
2830   DMGlobalToLocal - update local vectors from global vector
2831 
2832   Neighbor-wise Collective
2833 
2834   Input Parameters:
2835 + dm   - the `DM` object
2836 . g    - the global vector
2837 . mode - `INSERT_VALUES` or `ADD_VALUES`
2838 - l    - the local vector
2839 
2840   Level: beginner
2841 
2842   Notes:
2843   The communication involved in this update can be overlapped with computation by instead using
2844   `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.
2845 
2846   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2847 
2848 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2849           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`,
2850           `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2851 @*/
DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)2852 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2853 {
2854   PetscFunctionBegin;
2855   PetscCall(DMGlobalToLocalBegin(dm, g, mode, l));
2856   PetscCall(DMGlobalToLocalEnd(dm, g, mode, l));
2857   PetscFunctionReturn(PETSC_SUCCESS);
2858 }
2859 
2860 /*@
2861   DMGlobalToLocalBegin - Begins updating local vectors from global vector
2862 
2863   Neighbor-wise Collective
2864 
2865   Input Parameters:
2866 + dm   - the `DM` object
2867 . g    - the global vector
2868 . mode - `INSERT_VALUES` or `ADD_VALUES`
2869 - l    - the local vector
2870 
2871   Level: intermediate
2872 
2873   Notes:
2874   The operation is completed with `DMGlobalToLocalEnd()`
2875 
2876   One can perform local computations between the `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()` to overlap communication and computation
2877 
2878   `DMGlobalToLocal()` is a short form of  `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()`
2879 
2880   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2881 
2882 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2883 @*/
DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)2884 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2885 {
2886   PetscSF                 sf;
2887   DMGlobalToLocalHookLink link;
2888 
2889   PetscFunctionBegin;
2890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2891   for (link = dm->gtolhook; link; link = link->next) {
2892     if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx));
2893   }
2894   PetscCall(DMGetSectionSF(dm, &sf));
2895   if (sf) {
2896     const PetscScalar *gArray;
2897     PetscScalar       *lArray;
2898     PetscMemType       lmtype, gmtype;
2899 
2900     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2901     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2902     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2903     PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE));
2904     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2905     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2906   } else {
2907     PetscUseTypeMethod(dm, globaltolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2908   }
2909   PetscFunctionReturn(PETSC_SUCCESS);
2910 }
2911 
2912 /*@
2913   DMGlobalToLocalEnd - Ends updating local vectors from global vector
2914 
2915   Neighbor-wise Collective
2916 
2917   Input Parameters:
2918 + dm   - the `DM` object
2919 . g    - the global vector
2920 . mode - `INSERT_VALUES` or `ADD_VALUES`
2921 - l    - the local vector
2922 
2923   Level: intermediate
2924 
2925   Note:
2926   See `DMGlobalToLocalBegin()` for details.
2927 
2928 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2929 @*/
DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)2930 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2931 {
2932   PetscSF                 sf;
2933   const PetscScalar      *gArray;
2934   PetscScalar            *lArray;
2935   PetscBool               transform;
2936   DMGlobalToLocalHookLink link;
2937   PetscMemType            lmtype, gmtype;
2938 
2939   PetscFunctionBegin;
2940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2941   PetscCall(DMGetSectionSF(dm, &sf));
2942   PetscCall(DMHasBasisTransform(dm, &transform));
2943   if (sf) {
2944     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2945 
2946     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2947     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2948     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE));
2949     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2950     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2951     if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l));
2952   } else {
2953     PetscUseTypeMethod(dm, globaltolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2954   }
2955   PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL));
2956   for (link = dm->gtolhook; link; link = link->next) {
2957     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
2958   }
2959   PetscFunctionReturn(PETSC_SUCCESS);
2960 }
2961 
2962 /*@C
2963   DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2964 
2965   Logically Collective
2966 
2967   Input Parameters:
2968 + dm        - the `DM`
2969 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2970 . endhook   - function to run after `DMLocalToGlobalEnd()` has completed
2971 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2972 
2973   Calling sequence of `beginhook`:
2974 + global - global `DM`
2975 . l      - local vector
2976 . mode   - mode
2977 . g      - global vector
2978 - ctx    - optional user-defined function context
2979 
2980   Calling sequence of `endhook`:
2981 + global - global `DM`
2982 . l      - local vector
2983 . mode   - mode
2984 . g      - global vector
2985 - ctx    - optional user-defined function context
2986 
2987   Level: advanced
2988 
2989 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2990 @*/
DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (* beginhook)(DM global,Vec l,InsertMode mode,Vec g,PetscCtx ctx),PetscErrorCode (* endhook)(DM global,Vec l,InsertMode mode,Vec g,PetscCtx ctx),PetscCtx ctx)2991 PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM global, Vec l, InsertMode mode, Vec g, PetscCtx ctx), PetscErrorCode (*endhook)(DM global, Vec l, InsertMode mode, Vec g, PetscCtx ctx), PetscCtx ctx)
2992 {
2993   DMLocalToGlobalHookLink link, *p;
2994 
2995   PetscFunctionBegin;
2996   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2997   for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2998   PetscCall(PetscNew(&link));
2999   link->beginhook = beginhook;
3000   link->endhook   = endhook;
3001   link->ctx       = ctx;
3002   link->next      = NULL;
3003   *p              = link;
3004   PetscFunctionReturn(PETSC_SUCCESS);
3005 }
3006 
DMLocalToGlobalHook_Constraints(DM dm,Vec l,InsertMode mode,Vec g,PetscCtx ctx)3007 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, PetscCtx ctx)
3008 {
3009   PetscFunctionBegin;
3010   (void)g;
3011   (void)ctx;
3012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3013   if (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES) {
3014     Mat          cMat;
3015     Vec          cVec;
3016     PetscInt     nRows;
3017     PetscSection section, cSec;
3018     PetscInt     pStart, pEnd, p, dof;
3019 
3020     PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
3021     if (!cMat) PetscFunctionReturn(PETSC_SUCCESS);
3022 
3023     PetscCall(MatGetSize(cMat, &nRows, NULL));
3024     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
3025     PetscCall(DMGetLocalSection(dm, &section));
3026     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
3027     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
3028     for (p = pStart; p < pEnd; p++) {
3029       PetscCall(PetscSectionGetDof(cSec, p, &dof));
3030       if (dof) {
3031         PetscInt     d;
3032         PetscScalar *vals;
3033         PetscCall(VecGetValuesSection(l, section, p, &vals));
3034         PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode));
3035         /* for this to be the true transpose, we have to zero the values that
3036          * we just extracted */
3037         for (d = 0; d < dof; d++) vals[d] = 0.;
3038       }
3039     }
3040     PetscCall(MatMultTransposeAdd(cMat, cVec, l, l));
3041     PetscCall(VecDestroy(&cVec));
3042   }
3043   PetscFunctionReturn(PETSC_SUCCESS);
3044 }
3045 /*@
3046   DMLocalToGlobal - updates global vectors from local vectors
3047 
3048   Neighbor-wise Collective
3049 
3050   Input Parameters:
3051 + dm   - the `DM` object
3052 . l    - the local vector
3053 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3054 - g    - the global vector
3055 
3056   Level: beginner
3057 
3058   Notes:
3059   The communication involved in this update can be overlapped with computation by using
3060   `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.
3061 
3062   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3063 
3064   `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.
3065 
3066   Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process
3067 
3068 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()`
3069 @*/
DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)3070 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
3071 {
3072   PetscFunctionBegin;
3073   PetscCall(DMLocalToGlobalBegin(dm, l, mode, g));
3074   PetscCall(DMLocalToGlobalEnd(dm, l, mode, g));
3075   PetscFunctionReturn(PETSC_SUCCESS);
3076 }
3077 
3078 /*@
3079   DMLocalToGlobalBegin - begins updating global vectors from local vectors
3080 
3081   Neighbor-wise Collective
3082 
3083   Input Parameters:
3084 + dm   - the `DM` object
3085 . l    - the local vector
3086 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3087 - g    - the global vector
3088 
3089   Level: intermediate
3090 
3091   Notes:
3092   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3093 
3094   `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.
3095 
3096   Use `DMLocalToGlobalEnd()` to complete the communication process.
3097 
3098   `DMLocalToGlobal()` is a short form of  `DMLocalToGlobalBegin()` and  `DMLocalToGlobalEnd()`
3099 
3100   `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.
3101 
3102 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
3103 @*/
DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)3104 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
3105 {
3106   PetscSF                 sf;
3107   PetscSection            s, gs;
3108   DMLocalToGlobalHookLink link;
3109   Vec                     tmpl;
3110   const PetscScalar      *lArray;
3111   PetscScalar            *gArray;
3112   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
3113   PetscMemType            lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;
3114 
3115   PetscFunctionBegin;
3116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3117   for (link = dm->ltoghook; link; link = link->next) {
3118     if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx));
3119   }
3120   PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL));
3121   PetscCall(DMGetSectionSF(dm, &sf));
3122   PetscCall(DMGetLocalSection(dm, &s));
3123   switch (mode) {
3124   case INSERT_VALUES:
3125   case INSERT_ALL_VALUES:
3126   case INSERT_BC_VALUES:
3127     isInsert = PETSC_TRUE;
3128     break;
3129   case ADD_VALUES:
3130   case ADD_ALL_VALUES:
3131   case ADD_BC_VALUES:
3132     isInsert = PETSC_FALSE;
3133     break;
3134   default:
3135     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3136   }
3137   if ((sf && !isInsert) || (s && isInsert)) {
3138     PetscCall(DMHasBasisTransform(dm, &transform));
3139     if (transform) {
3140       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3141       PetscCall(VecCopy(l, tmpl));
3142       PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl));
3143       PetscCall(VecGetArrayRead(tmpl, &lArray));
3144     } else if (isInsert) {
3145       PetscCall(VecGetArrayRead(l, &lArray));
3146     } else {
3147       PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype));
3148       l_inplace = PETSC_TRUE;
3149     }
3150     if (s && isInsert) {
3151       PetscCall(VecGetArray(g, &gArray));
3152     } else {
3153       PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype));
3154       g_inplace = PETSC_TRUE;
3155     }
3156     if (sf && !isInsert) {
3157       PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM));
3158     } else if (s && isInsert) {
3159       PetscInt gStart, pStart, pEnd, p;
3160 
3161       PetscCall(DMGetGlobalSection(dm, &gs));
3162       PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
3163       PetscCall(VecGetOwnershipRange(g, &gStart, NULL));
3164       for (p = pStart; p < pEnd; ++p) {
3165         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
3166 
3167         PetscCall(PetscSectionGetDof(s, p, &dof));
3168         PetscCall(PetscSectionGetDof(gs, p, &gdof));
3169         PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
3170         PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof));
3171         PetscCall(PetscSectionGetOffset(s, p, &off));
3172         PetscCall(PetscSectionGetOffset(gs, p, &goff));
3173         /* Ignore off-process data and points with no global data */
3174         if (!gdof || goff < 0) continue;
3175         PetscCheck(dof == gdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3176         /* If no constraints are enforced in the global vector */
3177         if (!gcdof) {
3178           for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
3179           /* If constraints are enforced in the global vector */
3180         } else if (cdof == gcdof) {
3181           const PetscInt *cdofs;
3182           PetscInt        cind = 0;
3183 
3184           PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs));
3185           for (d = 0, e = 0; d < dof; ++d) {
3186             if ((cind < cdof) && (d == cdofs[cind])) {
3187               ++cind;
3188               continue;
3189             }
3190             gArray[goff - gStart + e++] = lArray[off + d];
3191           }
3192         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3193       }
3194     }
3195     if (g_inplace) {
3196       PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3197     } else {
3198       PetscCall(VecRestoreArray(g, &gArray));
3199     }
3200     if (transform) {
3201       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3202       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3203     } else if (l_inplace) {
3204       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3205     } else {
3206       PetscCall(VecRestoreArrayRead(l, &lArray));
3207     }
3208   } else {
3209     PetscUseTypeMethod(dm, localtoglobalbegin, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3210   }
3211   PetscFunctionReturn(PETSC_SUCCESS);
3212 }
3213 
3214 /*@
3215   DMLocalToGlobalEnd - updates global vectors from local vectors
3216 
3217   Neighbor-wise Collective
3218 
3219   Input Parameters:
3220 + dm   - the `DM` object
3221 . l    - the local vector
3222 . mode - `INSERT_VALUES` or `ADD_VALUES`
3223 - g    - the global vector
3224 
3225   Level: intermediate
3226 
3227   Note:
3228   See `DMLocalToGlobalBegin()` for full details
3229 
3230 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`
3231 @*/
DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)3232 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3233 {
3234   PetscSF                 sf;
3235   PetscSection            s;
3236   DMLocalToGlobalHookLink link;
3237   PetscBool               isInsert, transform;
3238 
3239   PetscFunctionBegin;
3240   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3241   PetscCall(DMGetSectionSF(dm, &sf));
3242   PetscCall(DMGetLocalSection(dm, &s));
3243   switch (mode) {
3244   case INSERT_VALUES:
3245   case INSERT_ALL_VALUES:
3246     isInsert = PETSC_TRUE;
3247     break;
3248   case ADD_VALUES:
3249   case ADD_ALL_VALUES:
3250     isInsert = PETSC_FALSE;
3251     break;
3252   default:
3253     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3254   }
3255   if (sf && !isInsert) {
3256     const PetscScalar *lArray;
3257     PetscScalar       *gArray;
3258     Vec                tmpl;
3259 
3260     PetscCall(DMHasBasisTransform(dm, &transform));
3261     if (transform) {
3262       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3263       PetscCall(VecGetArrayRead(tmpl, &lArray));
3264     } else {
3265       PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL));
3266     }
3267     PetscCall(VecGetArrayAndMemType(g, &gArray, NULL));
3268     PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM));
3269     if (transform) {
3270       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3271       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3272     } else {
3273       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3274     }
3275     PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3276   } else if (s && isInsert) {
3277   } else {
3278     PetscUseTypeMethod(dm, localtoglobalend, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3279   }
3280   for (link = dm->ltoghook; link; link = link->next) {
3281     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
3282   }
3283   PetscFunctionReturn(PETSC_SUCCESS);
3284 }
3285 
3286 /*@
3287   DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include
3288   ghost points that contain irrelevant values) to another local vector where the ghost points
3289   in the second are set correctly from values on other MPI ranks.
3290 
3291   Neighbor-wise Collective
3292 
3293   Input Parameters:
3294 + dm   - the `DM` object
3295 . g    - the original local vector
3296 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3297 
3298   Output Parameter:
3299 . l - the local vector with correct ghost values
3300 
3301   Level: intermediate
3302 
3303   Note:
3304   Must be followed by `DMLocalToLocalEnd()`.
3305 
3306 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3307 @*/
DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)3308 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3309 {
3310   PetscFunctionBegin;
3311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3312   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3313   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3314   PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3315   PetscFunctionReturn(PETSC_SUCCESS);
3316 }
3317 
3318 /*@
3319   DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3320   points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3321 
3322   Neighbor-wise Collective
3323 
3324   Input Parameters:
3325 + dm   - the `DM` object
3326 . g    - the original local vector
3327 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3328 
3329   Output Parameter:
3330 . l - the local vector with correct ghost values
3331 
3332   Level: intermediate
3333 
3334 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3335 @*/
DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)3336 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3337 {
3338   PetscFunctionBegin;
3339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3340   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3341   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3342   PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3343   PetscFunctionReturn(PETSC_SUCCESS);
3344 }
3345 
3346 /*@
3347   DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3348 
3349   Collective
3350 
3351   Input Parameters:
3352 + dm   - the `DM` object
3353 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
3354 
3355   Output Parameter:
3356 . dmc - the coarsened `DM`
3357 
3358   Level: developer
3359 
3360 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
3361           `DMCoarsenHookAdd()`, `DMCoarsenHookRemove()`
3362 @*/
DMCoarsen(DM dm,MPI_Comm comm,DM * dmc)3363 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3364 {
3365   DMCoarsenHookLink link;
3366 
3367   PetscFunctionBegin;
3368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3369   PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0));
3370   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3371   if (*dmc) {
3372     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3373     PetscCall(DMSetCoarseDM(dm, *dmc));
3374     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3375     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc));
3376     (*dmc)->ctx       = dm->ctx;
3377     (*dmc)->levelup   = dm->levelup;
3378     (*dmc)->leveldown = dm->leveldown + 1;
3379     PetscCall(DMSetMatType(*dmc, dm->mattype));
3380     for (link = dm->coarsenhook; link; link = link->next) {
3381       if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx));
3382     }
3383   }
3384   PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0));
3385   PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3386   PetscFunctionReturn(PETSC_SUCCESS);
3387 }
3388 
3389 /*@C
3390   DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3391 
3392   Logically Collective; No Fortran Support
3393 
3394   Input Parameters:
3395 + fine         - `DM` on which to run a hook when restricting to a coarser level
3396 . coarsenhook  - function to run when setting up a coarser level
3397 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3398 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3399 
3400   Calling sequence of `coarsenhook`:
3401 + fine   - fine level `DM`
3402 . coarse - coarse level `DM` to restrict problem to
3403 - ctx    - optional user-defined function context
3404 
3405   Calling sequence of `restricthook`:
3406 + fine      - fine level `DM`
3407 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3408 . rscale    - scaling vector for restriction
3409 . inject    - matrix restricting by injection
3410 . coarse    - coarse level DM to update
3411 - ctx       - optional user-defined function context
3412 
3413   Level: advanced
3414 
3415   Notes:
3416   This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.
3417 
3418   If this function is called multiple times, the hooks will be run in the order they are added.
3419 
3420   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3421   extract the finest level information from its context (instead of from the `SNES`).
3422 
3423   The hooks are automatically called by `DMRestrict()`
3424 
3425 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3426 @*/
DMCoarsenHookAdd(DM fine,PetscErrorCode (* coarsenhook)(DM fine,DM coarse,PetscCtx ctx),PetscErrorCode (* restricthook)(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,PetscCtx ctx),PetscCtx ctx)3427 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM fine, DM coarse, PetscCtx ctx), PetscErrorCode (*restricthook)(DM fine, Mat mrestrict, Vec rscale, Mat inject, DM coarse, PetscCtx ctx), PetscCtx ctx)
3428 {
3429   DMCoarsenHookLink link, *p;
3430 
3431   PetscFunctionBegin;
3432   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3433   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3434     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3435   }
3436   PetscCall(PetscNew(&link));
3437   link->coarsenhook  = coarsenhook;
3438   link->restricthook = restricthook;
3439   link->ctx          = ctx;
3440   link->next         = NULL;
3441   *p                 = link;
3442   PetscFunctionReturn(PETSC_SUCCESS);
3443 }
3444 
3445 /*@C
3446   DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3447 
3448   Logically Collective; No Fortran Support
3449 
3450   Input Parameters:
3451 + fine         - `DM` on which to run a hook when restricting to a coarser level
3452 . coarsenhook  - function to run when setting up a coarser level
3453 . restricthook - function to run to update data on coarser levels
3454 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3455 
3456   Level: advanced
3457 
3458   Notes:
3459   This function does nothing if the `coarsenhook` is not in the list.
3460 
3461   See `DMCoarsenHookAdd()` for the calling sequence of `coarsenhook` and `restricthook`
3462 
3463 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3464 @*/
DMCoarsenHookRemove(DM fine,PetscErrorCode (* coarsenhook)(DM,DM,void *),PetscErrorCode (* restricthook)(DM,Mat,Vec,Mat,DM,void *),PetscCtx ctx)3465 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), PetscCtx ctx)
3466 {
3467   DMCoarsenHookLink link, *p;
3468 
3469   PetscFunctionBegin;
3470   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3471   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3472     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3473       link = *p;
3474       *p   = link->next;
3475       PetscCall(PetscFree(link));
3476       break;
3477     }
3478   }
3479   PetscFunctionReturn(PETSC_SUCCESS);
3480 }
3481 
3482 /*@
3483   DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3484 
3485   Collective if any hooks are
3486 
3487   Input Parameters:
3488 + fine    - finer `DM` from which the data is obtained
3489 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3490 . rscale  - scaling vector for restriction
3491 . inject  - injection matrix, also use `MatRestrict()`
3492 - coarse  - coarser `DM` to update
3493 
3494   Level: developer
3495 
3496   Developer Note:
3497   Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3498 
3499 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3500 @*/
DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)3501 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3502 {
3503   DMCoarsenHookLink link;
3504 
3505   PetscFunctionBegin;
3506   for (link = fine->coarsenhook; link; link = link->next) {
3507     if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx));
3508   }
3509   PetscFunctionReturn(PETSC_SUCCESS);
3510 }
3511 
3512 /*@C
3513   DMSubDomainHookAdd - adds a callback to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3514 
3515   Logically Collective; No Fortran Support
3516 
3517   Input Parameters:
3518 + global       - global `DM`
3519 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3520 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3521 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3522 
3523   Calling sequence of `ddhook`:
3524 + global - global `DM`
3525 . block  - subdomain `DM`
3526 - ctx    - optional user-defined function context
3527 
3528   Calling sequence of `restricthook`:
3529 + global - global `DM`
3530 . out    - scatter to the outer (with ghost and overlap points) sub vector
3531 . in     - scatter to sub vector values only owned locally
3532 . block  - subdomain `DM`
3533 - ctx    - optional user-defined function context
3534 
3535   Level: advanced
3536 
3537   Notes:
3538   This function can be used if auxiliary data needs to be set up on subdomain `DM`s.
3539 
3540   If this function is called multiple times, the hooks will be run in the order they are added.
3541 
3542   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3543   extract the global information from its context (instead of from the `SNES`).
3544 
3545   Developer Note:
3546   It is unclear what "block solve" means within the definition of `restricthook`
3547 
3548 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, `DMCreateDomainDecomposition()`
3549 @*/
DMSubDomainHookAdd(DM global,PetscErrorCode (* ddhook)(DM global,DM block,PetscCtx ctx),PetscErrorCode (* restricthook)(DM global,VecScatter out,VecScatter in,DM block,PetscCtx ctx),PetscCtx ctx)3550 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM global, DM block, PetscCtx ctx), PetscErrorCode (*restricthook)(DM global, VecScatter out, VecScatter in, DM block, PetscCtx ctx), PetscCtx ctx)
3551 {
3552   DMSubDomainHookLink link, *p;
3553 
3554   PetscFunctionBegin;
3555   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3556   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3557     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3558   }
3559   PetscCall(PetscNew(&link));
3560   link->restricthook = restricthook;
3561   link->ddhook       = ddhook;
3562   link->ctx          = ctx;
3563   link->next         = NULL;
3564   *p                 = link;
3565   PetscFunctionReturn(PETSC_SUCCESS);
3566 }
3567 
3568 /*@C
3569   DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3570 
3571   Logically Collective; No Fortran Support
3572 
3573   Input Parameters:
3574 + global       - global `DM`
3575 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3576 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3577 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3578 
3579   Level: advanced
3580 
3581   Note:
3582   See `DMSubDomainHookAdd()` for the calling sequences of `ddhook` and `restricthook`
3583 
3584 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`,
3585           `DMCreateDomainDecomposition()`
3586 @*/
DMSubDomainHookRemove(DM global,PetscErrorCode (* ddhook)(DM,DM,void *),PetscErrorCode (* restricthook)(DM,VecScatter,VecScatter,DM,void *),PetscCtx ctx)3587 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), PetscCtx ctx)
3588 {
3589   DMSubDomainHookLink link, *p;
3590 
3591   PetscFunctionBegin;
3592   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3593   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3594     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3595       link = *p;
3596       *p   = link->next;
3597       PetscCall(PetscFree(link));
3598       break;
3599     }
3600   }
3601   PetscFunctionReturn(PETSC_SUCCESS);
3602 }
3603 
3604 /*@
3605   DMSubDomainRestrict - restricts user-defined problem data to a subdomain `DM` by running hooks registered by `DMSubDomainHookAdd()`
3606 
3607   Collective if any hooks are
3608 
3609   Input Parameters:
3610 + global   - The global `DM` to use as a base
3611 . oscatter - The scatter from domain global vector filling subdomain global vector with overlap
3612 . gscatter - The scatter from domain global vector filling subdomain local vector with ghosts
3613 - subdm    - The subdomain `DM` to update
3614 
3615   Level: developer
3616 
3617 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMCreateDomainDecomposition()`
3618 @*/
DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)3619 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3620 {
3621   DMSubDomainHookLink link;
3622 
3623   PetscFunctionBegin;
3624   for (link = global->subdomainhook; link; link = link->next) {
3625     if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx));
3626   }
3627   PetscFunctionReturn(PETSC_SUCCESS);
3628 }
3629 
3630 /*@
3631   DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3632 
3633   Not Collective
3634 
3635   Input Parameter:
3636 . dm - the `DM` object
3637 
3638   Output Parameter:
3639 . level - number of coarsenings
3640 
3641   Level: developer
3642 
3643 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3644 @*/
DMGetCoarsenLevel(DM dm,PetscInt * level)3645 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3646 {
3647   PetscFunctionBegin;
3648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3649   PetscAssertPointer(level, 2);
3650   *level = dm->leveldown;
3651   PetscFunctionReturn(PETSC_SUCCESS);
3652 }
3653 
3654 /*@
3655   DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3656 
3657   Collective
3658 
3659   Input Parameters:
3660 + dm    - the `DM` object
3661 - level - number of coarsenings
3662 
3663   Level: developer
3664 
3665   Note:
3666   This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3667 
3668 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3669 @*/
DMSetCoarsenLevel(DM dm,PetscInt level)3670 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3671 {
3672   PetscFunctionBegin;
3673   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3674   dm->leveldown = level;
3675   PetscFunctionReturn(PETSC_SUCCESS);
3676 }
3677 
3678 /*@
3679   DMRefineHierarchy - Refines a `DM` object, all levels at once
3680 
3681   Collective
3682 
3683   Input Parameters:
3684 + dm      - the `DM` object
3685 - nlevels - the number of levels of refinement
3686 
3687   Output Parameter:
3688 . dmf - the refined `DM` hierarchy
3689 
3690   Level: developer
3691 
3692 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3693 @*/
DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])3694 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3695 {
3696   PetscFunctionBegin;
3697   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3698   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3699   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3700   PetscAssertPointer(dmf, 3);
3701   if (dm->ops->refine && !dm->ops->refinehierarchy) {
3702     PetscInt i;
3703 
3704     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
3705     for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
3706   } else PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3707   PetscFunctionReturn(PETSC_SUCCESS);
3708 }
3709 
3710 /*@
3711   DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3712 
3713   Collective
3714 
3715   Input Parameters:
3716 + dm      - the `DM` object
3717 - nlevels - the number of levels of coarsening
3718 
3719   Output Parameter:
3720 . dmc - the coarsened `DM` hierarchy
3721 
3722   Level: developer
3723 
3724 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3725 @*/
DMCoarsenHierarchy(DM dm,PetscInt nlevels,DM dmc[])3726 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3727 {
3728   PetscFunctionBegin;
3729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3730   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3731   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3732   PetscAssertPointer(dmc, 3);
3733   if (dm->ops->coarsen && !dm->ops->coarsenhierarchy) {
3734     PetscInt i;
3735 
3736     PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
3737     for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
3738   } else PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3739   PetscFunctionReturn(PETSC_SUCCESS);
3740 }
3741 
3742 /*@C
3743   DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3744 
3745   Logically Collective if the function is collective
3746 
3747   Input Parameters:
3748 + dm      - the `DM` object
3749 - destroy - the destroy function, see `PetscCtxDestroyFn` for the calling sequence
3750 
3751   Level: intermediate
3752 
3753 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`,
3754           `DMGetApplicationContext()`, `PetscCtxDestroyFn`
3755 @*/
DMSetApplicationContextDestroy(DM dm,PetscCtxDestroyFn * destroy)3756 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscCtxDestroyFn *destroy)
3757 {
3758   PetscFunctionBegin;
3759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3760   dm->ctxdestroy = destroy;
3761   PetscFunctionReturn(PETSC_SUCCESS);
3762 }
3763 
3764 /*@
3765   DMSetApplicationContext - Set a user context into a `DM` object
3766 
3767   Not Collective
3768 
3769   Input Parameters:
3770 + dm  - the `DM` object
3771 - ctx - the user context
3772 
3773   Level: intermediate
3774 
3775   Note:
3776   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3777   In a multilevel solver, the user context is shared by all the `DM` in the hierarchy; it is thus not advisable
3778   to store objects that represent discretized quantities inside the context.
3779 
3780   Fortran Notes:
3781   This only works when the context is a Fortran derived type or a `PetscObject`. Declare `ctx` with
3782 .vb
3783   type(tUsertype), pointer :: ctx
3784 .ve
3785 
3786 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3787 @*/
DMSetApplicationContext(DM dm,PetscCtx ctx)3788 PetscErrorCode DMSetApplicationContext(DM dm, PetscCtx ctx)
3789 {
3790   PetscFunctionBegin;
3791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3792   dm->ctx = ctx;
3793   PetscFunctionReturn(PETSC_SUCCESS);
3794 }
3795 
3796 /*@
3797   DMGetApplicationContext - Gets a user context from a `DM` object provided with `DMSetApplicationContext()`
3798 
3799   Not Collective
3800 
3801   Input Parameter:
3802 . dm - the `DM` object
3803 
3804   Output Parameter:
3805 . ctx - a pointer to the user context
3806 
3807   Level: intermediate
3808 
3809   Note:
3810   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3811 
3812   Fortran Notes:
3813   This only works when the context is a Fortran derived type (it cannot be a `PetscObject`) and you **must** write a Fortran interface definition for this
3814   function that tells the Fortran compiler the derived data type that is returned as the `ctx` argument. For example,
3815 .vb
3816   Interface DMGetApplicationContext
3817     Subroutine DMGetApplicationContext(dm,ctx,ierr)
3818   #include <petsc/finclude/petscdm.h>
3819       use petscdm
3820       DM dm
3821       type(tUsertype), pointer :: ctx
3822       PetscErrorCode ierr
3823     End Subroutine
3824   End Interface DMGetApplicationContext
3825 .ve
3826 
3827   The prototype for `ctx` must be
3828 .vb
3829   type(tUsertype), pointer :: ctx
3830 .ve
3831 
3832 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3833 @*/
DMGetApplicationContext(DM dm,PetscCtxRt ctx)3834 PetscErrorCode DMGetApplicationContext(DM dm, PetscCtxRt ctx)
3835 {
3836   PetscFunctionBegin;
3837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3838   *(void **)ctx = dm->ctx;
3839   PetscFunctionReturn(PETSC_SUCCESS);
3840 }
3841 
3842 /*@C
3843   DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3844 
3845   Logically Collective
3846 
3847   Input Parameters:
3848 + dm - the DM object
3849 - f  - the function that computes variable bounds used by `SNESVI` (use `NULL` to cancel a previous function that was set)
3850 
3851   Level: intermediate
3852 
3853   Developer Note:
3854   Should be called `DMSetComputeVIBounds()` or something similar
3855 
3856 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3857          `DMSetJacobian()`
3858 @*/
DMSetVariableBounds(DM dm,PetscErrorCode (* f)(DM,Vec,Vec))3859 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3860 {
3861   PetscFunctionBegin;
3862   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3863   dm->ops->computevariablebounds = f;
3864   PetscFunctionReturn(PETSC_SUCCESS);
3865 }
3866 
3867 /*@
3868   DMHasVariableBounds - does the `DM` object have a variable bounds function?
3869 
3870   Not Collective
3871 
3872   Input Parameter:
3873 . dm - the `DM` object to destroy
3874 
3875   Output Parameter:
3876 . flg - `PETSC_TRUE` if the variable bounds function exists
3877 
3878   Level: developer
3879 
3880 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3881 @*/
DMHasVariableBounds(DM dm,PetscBool * flg)3882 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3883 {
3884   PetscFunctionBegin;
3885   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3886   PetscAssertPointer(flg, 2);
3887   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3888   PetscFunctionReturn(PETSC_SUCCESS);
3889 }
3890 
3891 /*@
3892   DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3893 
3894   Logically Collective
3895 
3896   Input Parameter:
3897 . dm - the `DM` object
3898 
3899   Output Parameters:
3900 + xl - lower bound
3901 - xu - upper bound
3902 
3903   Level: advanced
3904 
3905   Note:
3906   This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3907 
3908 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3909 @*/
DMComputeVariableBounds(DM dm,Vec xl,Vec xu)3910 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3911 {
3912   PetscFunctionBegin;
3913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3914   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3915   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3916   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3917   PetscFunctionReturn(PETSC_SUCCESS);
3918 }
3919 
3920 /*@
3921   DMHasColoring - does the `DM` object have a method of providing a coloring?
3922 
3923   Not Collective
3924 
3925   Input Parameter:
3926 . dm - the DM object
3927 
3928   Output Parameter:
3929 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3930 
3931   Level: developer
3932 
3933 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3934 @*/
DMHasColoring(DM dm,PetscBool * flg)3935 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3936 {
3937   PetscFunctionBegin;
3938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3939   PetscAssertPointer(flg, 2);
3940   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3941   PetscFunctionReturn(PETSC_SUCCESS);
3942 }
3943 
3944 /*@
3945   DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3946 
3947   Not Collective
3948 
3949   Input Parameter:
3950 . dm - the `DM` object
3951 
3952   Output Parameter:
3953 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3954 
3955   Level: developer
3956 
3957 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3958 @*/
DMHasCreateRestriction(DM dm,PetscBool * flg)3959 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3960 {
3961   PetscFunctionBegin;
3962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3963   PetscAssertPointer(flg, 2);
3964   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3965   PetscFunctionReturn(PETSC_SUCCESS);
3966 }
3967 
3968 /*@
3969   DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3970 
3971   Not Collective
3972 
3973   Input Parameter:
3974 . dm - the `DM` object
3975 
3976   Output Parameter:
3977 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3978 
3979   Level: developer
3980 
3981 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3982 @*/
DMHasCreateInjection(DM dm,PetscBool * flg)3983 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3984 {
3985   PetscFunctionBegin;
3986   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3987   PetscAssertPointer(flg, 2);
3988   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3989   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3990   PetscFunctionReturn(PETSC_SUCCESS);
3991 }
3992 
3993 PetscFunctionList DMList              = NULL;
3994 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3995 
3996 /*@
3997   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3998 
3999   Collective
4000 
4001   Input Parameters:
4002 + dm     - The `DM` object
4003 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
4004 
4005   Options Database Key:
4006 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
4007 
4008   Level: intermediate
4009 
4010   Note:
4011   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
4012 
4013 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
4014 @*/
DMSetType(DM dm,DMType method)4015 PetscErrorCode DMSetType(DM dm, DMType method)
4016 {
4017   PetscErrorCode (*r)(DM);
4018   PetscBool match;
4019 
4020   PetscFunctionBegin;
4021   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4022   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
4023   if (match) PetscFunctionReturn(PETSC_SUCCESS);
4024 
4025   PetscCall(DMRegisterAll());
4026   PetscCall(PetscFunctionListFind(DMList, method, &r));
4027   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
4028 
4029   PetscTryTypeMethod(dm, destroy);
4030   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
4031   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
4032   PetscCall((*r)(dm));
4033   PetscFunctionReturn(PETSC_SUCCESS);
4034 }
4035 
4036 /*@
4037   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
4038 
4039   Not Collective
4040 
4041   Input Parameter:
4042 . dm - The `DM`
4043 
4044   Output Parameter:
4045 . type - The `DMType` name
4046 
4047   Level: intermediate
4048 
4049 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
4050 @*/
DMGetType(DM dm,DMType * type)4051 PetscErrorCode DMGetType(DM dm, DMType *type)
4052 {
4053   PetscFunctionBegin;
4054   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4055   PetscAssertPointer(type, 2);
4056   PetscCall(DMRegisterAll());
4057   *type = ((PetscObject)dm)->type_name;
4058   PetscFunctionReturn(PETSC_SUCCESS);
4059 }
4060 
4061 /*@
4062   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
4063 
4064   Collective
4065 
4066   Input Parameters:
4067 + dm      - the `DM`
4068 - newtype - new `DM` type (use "same" for the same type)
4069 
4070   Output Parameter:
4071 . M - pointer to new `DM`
4072 
4073   Level: intermediate
4074 
4075   Note:
4076   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
4077   the MPI communicator of the generated `DM` is always the same as the communicator
4078   of the input `DM`.
4079 
4080 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
4081 @*/
DMConvert(DM dm,DMType newtype,DM * M)4082 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
4083 {
4084   DM        B;
4085   char      convname[256];
4086   PetscBool sametype /*, issame */;
4087 
4088   PetscFunctionBegin;
4089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4090   PetscValidType(dm, 1);
4091   PetscAssertPointer(M, 3);
4092   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4093   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4094   if (sametype) {
4095     *M = dm;
4096     PetscCall(PetscObjectReference((PetscObject)dm));
4097     PetscFunctionReturn(PETSC_SUCCESS);
4098   } else {
4099     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4100 
4101     /*
4102        Order of precedence:
4103        1) See if a specialized converter is known to the current DM.
4104        2) See if a specialized converter is known to the desired DM class.
4105        3) See if a good general converter is registered for the desired class
4106        4) See if a good general converter is known for the current matrix.
4107        5) Use a really basic converter.
4108     */
4109 
4110     /* 1) See if a specialized converter is known to the current DM and the desired class */
4111     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4112     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4113     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4114     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4115     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4116     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4117     if (conv) goto foundconv;
4118 
4119     /* 2)  See if a specialized converter is known to the desired DM class. */
4120     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4121     PetscCall(DMSetType(B, newtype));
4122     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4123     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4124     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4125     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4126     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4127     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4128     if (conv) {
4129       PetscCall(DMDestroy(&B));
4130       goto foundconv;
4131     }
4132 
4133 #if 0
4134     /* 3) See if a good general converter is registered for the desired class */
4135     conv = B->ops->convertfrom;
4136     PetscCall(DMDestroy(&B));
4137     if (conv) goto foundconv;
4138 
4139     /* 4) See if a good general converter is known for the current matrix */
4140     if (dm->ops->convert) conv = dm->ops->convert;
4141     if (conv) goto foundconv;
4142 #endif
4143 
4144     /* 5) Use a really basic converter. */
4145     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4146 
4147   foundconv:
4148     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4149     PetscCall((*conv)(dm, newtype, M));
4150     /* Things that are independent of DM type: We should consult DMClone() here */
4151     {
4152       const PetscReal *maxCell, *Lstart, *L;
4153 
4154       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4155       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4156       (*M)->prealloc_only = dm->prealloc_only;
4157       PetscCall(PetscFree((*M)->vectype));
4158       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4159       PetscCall(PetscFree((*M)->mattype));
4160       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4161     }
4162     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4163   }
4164   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4165   PetscFunctionReturn(PETSC_SUCCESS);
4166 }
4167 
4168 /*@C
4169   DMRegister -  Adds a new `DM` type implementation
4170 
4171   Not Collective, No Fortran Support
4172 
4173   Input Parameters:
4174 + sname    - The name of a new user-defined creation routine
4175 - function - The creation routine itself
4176 
4177   Level: advanced
4178 
4179   Note:
4180   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4181 
4182   Example Usage:
4183 .vb
4184     DMRegister("my_da", MyDMCreate);
4185 .ve
4186 
4187   Then, your `DM` type can be chosen with the procedural interface via
4188 .vb
4189     DMCreate(MPI_Comm, DM *);
4190     DMSetType(DM,"my_da");
4191 .ve
4192   or at runtime via the option
4193 .vb
4194     -da_type my_da
4195 .ve
4196 
4197 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4198 @*/
DMRegister(const char sname[],PetscErrorCode (* function)(DM))4199 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4200 {
4201   PetscFunctionBegin;
4202   PetscCall(DMInitializePackage());
4203   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4204   PetscFunctionReturn(PETSC_SUCCESS);
4205 }
4206 
4207 /*@
4208   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4209 
4210   Collective
4211 
4212   Input Parameters:
4213 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4214            some related function before a call to `DMLoad()`.
4215 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4216            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4217 
4218   Level: intermediate
4219 
4220   Notes:
4221   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4222 
4223   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4224   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4225   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4226 
4227 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4228 @*/
DMLoad(DM newdm,PetscViewer viewer)4229 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4230 {
4231   PetscBool isbinary, ishdf5;
4232 
4233   PetscFunctionBegin;
4234   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4235   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4236   PetscCall(PetscViewerCheckReadable(viewer));
4237   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4238   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4239   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4240   if (isbinary) {
4241     PetscInt classid;
4242     char     type[256];
4243 
4244     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4245     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid);
4246     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4247     PetscCall(DMSetType(newdm, type));
4248     PetscTryTypeMethod(newdm, load, viewer);
4249   } else if (ishdf5) {
4250     PetscTryTypeMethod(newdm, load, viewer);
4251   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4252   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4253   PetscFunctionReturn(PETSC_SUCCESS);
4254 }
4255 
4256 /* FEM Support */
4257 
DMPrintCellIndices(PetscInt c,const char name[],PetscInt len,const PetscInt x[])4258 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4259 {
4260   PetscInt f;
4261 
4262   PetscFunctionBegin;
4263   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4264   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4265   PetscFunctionReturn(PETSC_SUCCESS);
4266 }
4267 
DMPrintCellVector(PetscInt c,const char name[],PetscInt len,const PetscScalar x[])4268 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4269 {
4270   PetscInt f;
4271 
4272   PetscFunctionBegin;
4273   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4274   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4275   PetscFunctionReturn(PETSC_SUCCESS);
4276 }
4277 
DMPrintCellVectorReal(PetscInt c,const char name[],PetscInt len,const PetscReal x[])4278 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4279 {
4280   PetscInt f;
4281 
4282   PetscFunctionBegin;
4283   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4284   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4285   PetscFunctionReturn(PETSC_SUCCESS);
4286 }
4287 
DMPrintCellMatrix(PetscInt c,const char name[],PetscInt rows,PetscInt cols,const PetscScalar A[])4288 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4289 {
4290   PetscInt f, g;
4291 
4292   PetscFunctionBegin;
4293   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4294   for (f = 0; f < rows; ++f) {
4295     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4296     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4297     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4298   }
4299   PetscFunctionReturn(PETSC_SUCCESS);
4300 }
4301 
DMPrintLocalVec(DM dm,const char name[],PetscReal tol,Vec X)4302 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4303 {
4304   PetscInt           localSize, bs;
4305   PetscMPIInt        size;
4306   Vec                x, xglob;
4307   const PetscScalar *xarray;
4308 
4309   PetscFunctionBegin;
4310   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4311   PetscCall(VecDuplicate(X, &x));
4312   PetscCall(VecCopy(X, x));
4313   PetscCall(VecFilter(x, tol));
4314   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4315   if (size > 1) {
4316     PetscCall(VecGetLocalSize(x, &localSize));
4317     PetscCall(VecGetArrayRead(x, &xarray));
4318     PetscCall(VecGetBlockSize(x, &bs));
4319     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4320   } else {
4321     xglob = x;
4322   }
4323   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4324   if (size > 1) {
4325     PetscCall(VecDestroy(&xglob));
4326     PetscCall(VecRestoreArrayRead(x, &xarray));
4327   }
4328   PetscCall(VecDestroy(&x));
4329   PetscFunctionReturn(PETSC_SUCCESS);
4330 }
4331 
4332 /*@
4333   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4334 
4335   Input Parameter:
4336 . dm - The `DM`
4337 
4338   Output Parameter:
4339 . section - The `PetscSection`
4340 
4341   Options Database Key:
4342 . -dm_petscsection_view - View the section created by the `DM`
4343 
4344   Level: intermediate
4345 
4346   Note:
4347   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4348 
4349 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4350 @*/
DMGetLocalSection(DM dm,PetscSection * section)4351 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4352 {
4353   PetscFunctionBegin;
4354   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4355   PetscAssertPointer(section, 2);
4356   if (!dm->localSection && dm->ops->createlocalsection) {
4357     PetscInt d;
4358 
4359     if (dm->setfromoptionscalled) {
4360       PetscObject       obj = (PetscObject)dm;
4361       PetscViewer       viewer;
4362       PetscViewerFormat format;
4363       PetscBool         flg;
4364 
4365       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4366       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4367       for (d = 0; d < dm->Nds; ++d) {
4368         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4369         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4370       }
4371       if (flg) {
4372         PetscCall(PetscViewerFlush(viewer));
4373         PetscCall(PetscViewerPopFormat(viewer));
4374         PetscCall(PetscViewerDestroy(&viewer));
4375       }
4376     }
4377     PetscUseTypeMethod(dm, createlocalsection);
4378     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4379   }
4380   *section = dm->localSection;
4381   PetscFunctionReturn(PETSC_SUCCESS);
4382 }
4383 
4384 /*@
4385   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4386 
4387   Input Parameters:
4388 + dm      - The `DM`
4389 - section - The `PetscSection`
4390 
4391   Level: intermediate
4392 
4393   Note:
4394   Any existing Section will be destroyed
4395 
4396 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4397 @*/
DMSetLocalSection(DM dm,PetscSection section)4398 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4399 {
4400   PetscInt numFields = 0;
4401   PetscInt f;
4402 
4403   PetscFunctionBegin;
4404   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4405   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4406   PetscCall(PetscObjectReference((PetscObject)section));
4407   PetscCall(PetscSectionDestroy(&dm->localSection));
4408   dm->localSection = section;
4409   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4410   if (numFields) {
4411     PetscCall(DMSetNumFields(dm, numFields));
4412     for (f = 0; f < numFields; ++f) {
4413       PetscObject disc;
4414       const char *name;
4415 
4416       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4417       PetscCall(DMGetField(dm, f, NULL, &disc));
4418       PetscCall(PetscObjectSetName(disc, name));
4419     }
4420   }
4421   /* The global section and the SectionSF will be rebuilt
4422      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4423   PetscCall(PetscSectionDestroy(&dm->globalSection));
4424   PetscCall(PetscSFDestroy(&dm->sectionSF));
4425   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4426 
4427   /* Clear scratch vectors */
4428   PetscCall(DMClearGlobalVectors(dm));
4429   PetscCall(DMClearLocalVectors(dm));
4430   PetscCall(DMClearNamedGlobalVectors(dm));
4431   PetscCall(DMClearNamedLocalVectors(dm));
4432   PetscFunctionReturn(PETSC_SUCCESS);
4433 }
4434 
4435 /*@C
4436   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4437 
4438   Input Parameter:
4439 . dm - The `DM`
4440 
4441   Output Parameters:
4442 + perm        - A permutation of the mesh points in the chart
4443 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4444 
4445   Level: developer
4446 
4447 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4448 @*/
DMCreateSectionPermutation(DM dm,IS * perm,PetscBT * blockStarts)4449 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4450 {
4451   PetscFunctionBegin;
4452   *perm        = NULL;
4453   *blockStarts = NULL;
4454   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4455   PetscFunctionReturn(PETSC_SUCCESS);
4456 }
4457 
4458 /*@
4459   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4460 
4461   not Collective
4462 
4463   Input Parameter:
4464 . dm - The `DM`
4465 
4466   Output Parameters:
4467 + section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Returns `NULL` if there are no local constraints.
4468 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section.  Returns `NULL` if there are no local constraints.
4469 - bias    - Vector containing bias to be added to constrained dofs
4470 
4471   Level: advanced
4472 
4473   Note:
4474   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4475 
4476 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4477 @*/
DMGetDefaultConstraints(DM dm,PetscSection * section,Mat * mat,Vec * bias)4478 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4479 {
4480   PetscFunctionBegin;
4481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4482   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4483   if (section) *section = dm->defaultConstraint.section;
4484   if (mat) *mat = dm->defaultConstraint.mat;
4485   if (bias) *bias = dm->defaultConstraint.bias;
4486   PetscFunctionReturn(PETSC_SUCCESS);
4487 }
4488 
4489 /*@
4490   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4491 
4492   Collective
4493 
4494   Input Parameters:
4495 + dm      - The `DM`
4496 . section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4497 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section:  `NULL` indicates no constraints.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4498 - bias    - A bias vector to be added to constrained values in the local vector.  `NULL` indicates no bias.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4499 
4500   Level: advanced
4501 
4502   Notes:
4503   If a constraint matrix is specified, then it is applied during `DMGlobalToLocalEnd()` when mode is `INSERT_VALUES`, `INSERT_BC_VALUES`, or `INSERT_ALL_VALUES`.  Without a constraint matrix, the local vector l returned by `DMGlobalToLocalEnd()` contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`.
4504 
4505   If a constraint matrix is specified, then its adjoint is applied during `DMLocalToGlobalBegin()` when mode is `ADD_VALUES`, `ADD_BC_VALUES`, or `ADD_ALL_VALUES`.  Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above.  Any bias, if specified, is ignored when accumulating.
4506 
4507   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4508 
4509 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4510 @*/
DMSetDefaultConstraints(DM dm,PetscSection section,Mat mat,Vec bias)4511 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4512 {
4513   PetscMPIInt result;
4514 
4515   PetscFunctionBegin;
4516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4517   if (section) {
4518     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4519     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4520     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4521   }
4522   if (mat) {
4523     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4524     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4525     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4526   }
4527   if (bias) {
4528     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4529     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4530     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4531   }
4532   PetscCall(PetscObjectReference((PetscObject)section));
4533   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4534   dm->defaultConstraint.section = section;
4535   PetscCall(PetscObjectReference((PetscObject)mat));
4536   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4537   dm->defaultConstraint.mat = mat;
4538   PetscCall(PetscObjectReference((PetscObject)bias));
4539   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4540   dm->defaultConstraint.bias = bias;
4541   PetscFunctionReturn(PETSC_SUCCESS);
4542 }
4543 
4544 #if defined(PETSC_USE_DEBUG)
4545 /*
4546   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4547 
4548   Input Parameters:
4549 + dm - The `DM`
4550 . localSection - `PetscSection` describing the local data layout
4551 - globalSection - `PetscSection` describing the global data layout
4552 
4553   Level: intermediate
4554 
4555 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4556 */
DMDefaultSectionCheckConsistency_Internal(DM dm,PetscSection localSection,PetscSection globalSection)4557 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4558 {
4559   MPI_Comm        comm;
4560   PetscLayout     layout;
4561   const PetscInt *ranges;
4562   PetscInt        pStart, pEnd, p, nroots;
4563   PetscMPIInt     size, rank;
4564   PetscBool       valid = PETSC_TRUE, gvalid;
4565 
4566   PetscFunctionBegin;
4567   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4569   PetscCallMPI(MPI_Comm_size(comm, &size));
4570   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4571   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4572   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4573   PetscCall(PetscLayoutCreate(comm, &layout));
4574   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4575   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4576   PetscCall(PetscLayoutSetUp(layout));
4577   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4578   for (p = pStart; p < pEnd; ++p) {
4579     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4580 
4581     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4582     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4583     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4584     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4585     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4586     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4587     if (!gdof) continue; /* Censored point */
4588     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4589       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4590       valid = PETSC_FALSE;
4591     }
4592     if (gcdof && (gcdof != cdof)) {
4593       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4594       valid = PETSC_FALSE;
4595     }
4596     if (gdof < 0) {
4597       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4598       for (d = 0; d < gsize; ++d) {
4599         PetscInt offset = -(goff + 1) + d, r;
4600 
4601         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4602         if (r < 0) r = -(r + 2);
4603         if ((r < 0) || (r >= size)) {
4604           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4605           valid = PETSC_FALSE;
4606           break;
4607         }
4608       }
4609     }
4610   }
4611   PetscCall(PetscLayoutDestroy(&layout));
4612   PetscCall(PetscSynchronizedFlush(comm, NULL));
4613   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPI_C_BOOL, MPI_LAND, comm));
4614   if (!gvalid) {
4615     PetscCall(DMView(dm, NULL));
4616     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4617   }
4618   PetscFunctionReturn(PETSC_SUCCESS);
4619 }
4620 #endif
4621 
DMGetIsoperiodicPointSF_Internal(DM dm,PetscSF * sf)4622 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4623 {
4624   PetscErrorCode (*f)(DM, PetscSF *);
4625 
4626   PetscFunctionBegin;
4627   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4628   PetscAssertPointer(sf, 2);
4629   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4630   if (f) PetscCall(f(dm, sf));
4631   else *sf = dm->sf;
4632   PetscFunctionReturn(PETSC_SUCCESS);
4633 }
4634 
4635 /*@
4636   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4637 
4638   Collective
4639 
4640   Input Parameter:
4641 . dm - The `DM`
4642 
4643   Output Parameter:
4644 . section - The `PetscSection`
4645 
4646   Level: intermediate
4647 
4648   Note:
4649   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4650 
4651 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4652 @*/
DMGetGlobalSection(DM dm,PetscSection * section)4653 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4654 {
4655   PetscFunctionBegin;
4656   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4657   PetscAssertPointer(section, 2);
4658   if (!dm->globalSection) {
4659     PetscSection s;
4660     PetscSF      sf;
4661 
4662     PetscCall(DMGetLocalSection(dm, &s));
4663     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4664     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4665     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4666     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4667     PetscCall(PetscLayoutDestroy(&dm->map));
4668     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4669     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4670   }
4671   *section = dm->globalSection;
4672   PetscFunctionReturn(PETSC_SUCCESS);
4673 }
4674 
4675 /*@
4676   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4677 
4678   Input Parameters:
4679 + dm      - The `DM`
4680 - section - The PetscSection, or `NULL`
4681 
4682   Level: intermediate
4683 
4684   Note:
4685   Any existing `PetscSection` will be destroyed
4686 
4687 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4688 @*/
DMSetGlobalSection(DM dm,PetscSection section)4689 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4690 {
4691   PetscFunctionBegin;
4692   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4693   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4694   PetscCall(PetscObjectReference((PetscObject)section));
4695   PetscCall(PetscSectionDestroy(&dm->globalSection));
4696   dm->globalSection = section;
4697 #if defined(PETSC_USE_DEBUG)
4698   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4699 #endif
4700   /* Clear global scratch vectors and sectionSF */
4701   PetscCall(PetscSFDestroy(&dm->sectionSF));
4702   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4703   PetscCall(DMClearGlobalVectors(dm));
4704   PetscCall(DMClearNamedGlobalVectors(dm));
4705   PetscFunctionReturn(PETSC_SUCCESS);
4706 }
4707 
4708 /*@
4709   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4710   it is created from the default `PetscSection` layouts in the `DM`.
4711 
4712   Input Parameter:
4713 . dm - The `DM`
4714 
4715   Output Parameter:
4716 . sf - The `PetscSF`
4717 
4718   Level: intermediate
4719 
4720   Note:
4721   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4722 
4723 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4724 @*/
DMGetSectionSF(DM dm,PetscSF * sf)4725 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4726 {
4727   PetscInt nroots;
4728 
4729   PetscFunctionBegin;
4730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4731   PetscAssertPointer(sf, 2);
4732   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4733   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4734   if (nroots < 0) {
4735     PetscSection section, gSection;
4736 
4737     PetscCall(DMGetLocalSection(dm, &section));
4738     if (section) {
4739       PetscCall(DMGetGlobalSection(dm, &gSection));
4740       PetscCall(DMCreateSectionSF(dm, section, gSection));
4741     } else {
4742       *sf = NULL;
4743       PetscFunctionReturn(PETSC_SUCCESS);
4744     }
4745   }
4746   *sf = dm->sectionSF;
4747   PetscFunctionReturn(PETSC_SUCCESS);
4748 }
4749 
4750 /*@
4751   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4752 
4753   Input Parameters:
4754 + dm - The `DM`
4755 - sf - The `PetscSF`
4756 
4757   Level: intermediate
4758 
4759   Note:
4760   Any previous `PetscSF` is destroyed
4761 
4762 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4763 @*/
DMSetSectionSF(DM dm,PetscSF sf)4764 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4765 {
4766   PetscFunctionBegin;
4767   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4768   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4769   PetscCall(PetscObjectReference((PetscObject)sf));
4770   PetscCall(PetscSFDestroy(&dm->sectionSF));
4771   dm->sectionSF = sf;
4772   PetscFunctionReturn(PETSC_SUCCESS);
4773 }
4774 
4775 /*@
4776   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4777   describing the data layout.
4778 
4779   Input Parameters:
4780 + dm            - The `DM`
4781 . localSection  - `PetscSection` describing the local data layout
4782 - globalSection - `PetscSection` describing the global data layout
4783 
4784   Level: developer
4785 
4786   Note:
4787   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4788 
4789   Developer Note:
4790   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4791   directly into the `DM`, perhaps this function should not take the local and global sections as
4792   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4793   they create, this returns nothing
4794 
4795 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4796 @*/
DMCreateSectionSF(DM dm,PetscSection localSection,PetscSection globalSection)4797 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4798 {
4799   PetscFunctionBegin;
4800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4801   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4802   PetscFunctionReturn(PETSC_SUCCESS);
4803 }
4804 
4805 /*@
4806   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4807 
4808   Not collective but the resulting `PetscSF` is collective
4809 
4810   Input Parameter:
4811 . dm - The `DM`
4812 
4813   Output Parameter:
4814 . sf - The `PetscSF`
4815 
4816   Level: intermediate
4817 
4818   Note:
4819   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4820 
4821 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4822 @*/
DMGetPointSF(DM dm,PetscSF * sf)4823 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4824 {
4825   PetscFunctionBegin;
4826   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4827   PetscAssertPointer(sf, 2);
4828   *sf = dm->sf;
4829   PetscFunctionReturn(PETSC_SUCCESS);
4830 }
4831 
4832 /*@
4833   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4834 
4835   Collective
4836 
4837   Input Parameters:
4838 + dm - The `DM`
4839 - sf - The `PetscSF`
4840 
4841   Level: intermediate
4842 
4843 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4844 @*/
DMSetPointSF(DM dm,PetscSF sf)4845 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4846 {
4847   PetscFunctionBegin;
4848   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4849   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4850   PetscCall(PetscObjectReference((PetscObject)sf));
4851   PetscCall(PetscSFDestroy(&dm->sf));
4852   dm->sf = sf;
4853   PetscFunctionReturn(PETSC_SUCCESS);
4854 }
4855 
4856 /*@
4857   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4858 
4859   Input Parameter:
4860 . dm - The `DM`
4861 
4862   Output Parameter:
4863 . sf - The `PetscSF`
4864 
4865   Level: intermediate
4866 
4867   Note:
4868   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4869 
4870 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4871 @*/
DMGetNaturalSF(DM dm,PetscSF * sf)4872 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4873 {
4874   PetscFunctionBegin;
4875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4876   PetscAssertPointer(sf, 2);
4877   *sf = dm->sfNatural;
4878   PetscFunctionReturn(PETSC_SUCCESS);
4879 }
4880 
4881 /*@
4882   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4883 
4884   Input Parameters:
4885 + dm - The DM
4886 - sf - The PetscSF
4887 
4888   Level: intermediate
4889 
4890 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4891 @*/
DMSetNaturalSF(DM dm,PetscSF sf)4892 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4893 {
4894   PetscFunctionBegin;
4895   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4896   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4897   PetscCall(PetscObjectReference((PetscObject)sf));
4898   PetscCall(PetscSFDestroy(&dm->sfNatural));
4899   dm->sfNatural = sf;
4900   PetscFunctionReturn(PETSC_SUCCESS);
4901 }
4902 
DMSetDefaultAdjacency_Private(DM dm,PetscInt f,PetscObject disc)4903 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4904 {
4905   PetscClassId id;
4906 
4907   PetscFunctionBegin;
4908   PetscCall(PetscObjectGetClassId(disc, &id));
4909   if (id == PETSCFE_CLASSID) {
4910     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4911   } else if (id == PETSCFV_CLASSID) {
4912     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4913   } else {
4914     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4915   }
4916   PetscFunctionReturn(PETSC_SUCCESS);
4917 }
4918 
DMFieldEnlarge_Static(DM dm,PetscInt NfNew)4919 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4920 {
4921   RegionField *tmpr;
4922   PetscInt     Nf = dm->Nf, f;
4923 
4924   PetscFunctionBegin;
4925   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4926   PetscCall(PetscMalloc1(NfNew, &tmpr));
4927   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4928   for (f = Nf; f < NfNew; ++f) {
4929     tmpr[f].disc        = NULL;
4930     tmpr[f].label       = NULL;
4931     tmpr[f].avoidTensor = PETSC_FALSE;
4932   }
4933   PetscCall(PetscFree(dm->fields));
4934   dm->Nf     = NfNew;
4935   dm->fields = tmpr;
4936   PetscFunctionReturn(PETSC_SUCCESS);
4937 }
4938 
4939 /*@
4940   DMClearFields - Remove all fields from the `DM`
4941 
4942   Logically Collective
4943 
4944   Input Parameter:
4945 . dm - The `DM`
4946 
4947   Level: intermediate
4948 
4949 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4950 @*/
DMClearFields(DM dm)4951 PetscErrorCode DMClearFields(DM dm)
4952 {
4953   PetscInt f;
4954 
4955   PetscFunctionBegin;
4956   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4957   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); // DMDA does not use fields field in DM
4958   for (f = 0; f < dm->Nf; ++f) {
4959     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4960     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4961   }
4962   PetscCall(PetscFree(dm->fields));
4963   dm->fields = NULL;
4964   dm->Nf     = 0;
4965   PetscFunctionReturn(PETSC_SUCCESS);
4966 }
4967 
4968 /*@
4969   DMGetNumFields - Get the number of fields in the `DM`
4970 
4971   Not Collective
4972 
4973   Input Parameter:
4974 . dm - The `DM`
4975 
4976   Output Parameter:
4977 . numFields - The number of fields
4978 
4979   Level: intermediate
4980 
4981 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4982 @*/
DMGetNumFields(DM dm,PetscInt * numFields)4983 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4984 {
4985   PetscFunctionBegin;
4986   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4987   PetscAssertPointer(numFields, 2);
4988   *numFields = dm->Nf;
4989   PetscFunctionReturn(PETSC_SUCCESS);
4990 }
4991 
4992 /*@
4993   DMSetNumFields - Set the number of fields in the `DM`
4994 
4995   Logically Collective
4996 
4997   Input Parameters:
4998 + dm        - The `DM`
4999 - numFields - The number of fields
5000 
5001   Level: intermediate
5002 
5003 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
5004 @*/
DMSetNumFields(DM dm,PetscInt numFields)5005 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
5006 {
5007   PetscInt Nf, f;
5008 
5009   PetscFunctionBegin;
5010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5011   PetscCall(DMGetNumFields(dm, &Nf));
5012   for (f = Nf; f < numFields; ++f) {
5013     PetscContainer obj;
5014 
5015     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
5016     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
5017     PetscCall(PetscContainerDestroy(&obj));
5018   }
5019   PetscFunctionReturn(PETSC_SUCCESS);
5020 }
5021 
5022 /*@
5023   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5024 
5025   Not Collective
5026 
5027   Input Parameters:
5028 + dm - The `DM`
5029 - f  - The field number
5030 
5031   Output Parameters:
5032 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5033 - disc  - The discretization object (pass in `NULL` if not needed)
5034 
5035   Level: intermediate
5036 
5037 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5038 @*/
DMGetField(DM dm,PetscInt f,DMLabel * label,PetscObject * disc)5039 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5040 {
5041   PetscFunctionBegin;
5042   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5043   PetscAssertPointer(disc, 4);
5044   PetscCheck((f >= 0) && (f < dm->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, dm->Nf);
5045   if (!dm->fields) {
5046     if (label) *label = NULL;
5047     if (disc) *disc = NULL;
5048   } else { // some DM such as DMDA do not have dm->fields
5049     if (label) *label = dm->fields[f].label;
5050     if (disc) *disc = dm->fields[f].disc;
5051   }
5052   PetscFunctionReturn(PETSC_SUCCESS);
5053 }
5054 
5055 /* Does not clear the DS */
DMSetField_Internal(DM dm,PetscInt f,DMLabel label,PetscObject disc)5056 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5057 {
5058   PetscFunctionBegin;
5059   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5060   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5061   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5062   dm->fields[f].label = label;
5063   dm->fields[f].disc  = disc;
5064   PetscCall(PetscObjectReference((PetscObject)label));
5065   PetscCall(PetscObjectReference(disc));
5066   PetscFunctionReturn(PETSC_SUCCESS);
5067 }
5068 
5069 /*@
5070   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5071   the field numbering.
5072 
5073   Logically Collective
5074 
5075   Input Parameters:
5076 + dm    - The `DM`
5077 . f     - The field number
5078 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5079 - disc  - The discretization object
5080 
5081   Level: intermediate
5082 
5083 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5084 @*/
DMSetField(DM dm,PetscInt f,DMLabel label,PetscObject disc)5085 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5086 {
5087   PetscFunctionBegin;
5088   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5089   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5090   PetscValidHeader(disc, 4);
5091   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5092   PetscCall(DMSetField_Internal(dm, f, label, disc));
5093   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5094   PetscCall(DMClearDS(dm));
5095   PetscFunctionReturn(PETSC_SUCCESS);
5096 }
5097 
5098 /*@
5099   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5100   and a discretization object that defines the function space associated with those points.
5101 
5102   Logically Collective
5103 
5104   Input Parameters:
5105 + dm    - The `DM`
5106 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5107 - disc  - The discretization object
5108 
5109   Level: intermediate
5110 
5111   Notes:
5112   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5113 
5114   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5115   within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
5116   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5117 
5118   Fortran Note:
5119   Use the argument `PetscObjectCast(disc)` as the second argument
5120 
5121 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5122 @*/
DMAddField(DM dm,DMLabel label,PetscObject disc)5123 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5124 {
5125   PetscInt Nf = dm->Nf;
5126 
5127   PetscFunctionBegin;
5128   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5129   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5130   PetscValidHeader(disc, 3);
5131   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5132   dm->fields[Nf].label = label;
5133   dm->fields[Nf].disc  = disc;
5134   PetscCall(PetscObjectReference((PetscObject)label));
5135   PetscCall(PetscObjectReference(disc));
5136   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5137   PetscCall(DMClearDS(dm));
5138   PetscFunctionReturn(PETSC_SUCCESS);
5139 }
5140 
5141 /*@
5142   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5143 
5144   Logically Collective
5145 
5146   Input Parameters:
5147 + dm          - The `DM`
5148 . f           - The field index
5149 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5150 
5151   Level: intermediate
5152 
5153 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5154 @*/
DMSetFieldAvoidTensor(DM dm,PetscInt f,PetscBool avoidTensor)5155 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5156 {
5157   PetscFunctionBegin;
5158   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5159   dm->fields[f].avoidTensor = avoidTensor;
5160   PetscFunctionReturn(PETSC_SUCCESS);
5161 }
5162 
5163 /*@
5164   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5165 
5166   Not Collective
5167 
5168   Input Parameters:
5169 + dm - The `DM`
5170 - f  - The field index
5171 
5172   Output Parameter:
5173 . avoidTensor - The flag to avoid defining the field on tensor cells
5174 
5175   Level: intermediate
5176 
5177 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5178 @*/
DMGetFieldAvoidTensor(DM dm,PetscInt f,PetscBool * avoidTensor)5179 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5180 {
5181   PetscFunctionBegin;
5182   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5183   *avoidTensor = dm->fields[f].avoidTensor;
5184   PetscFunctionReturn(PETSC_SUCCESS);
5185 }
5186 
5187 /*@
5188   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5189 
5190   Collective
5191 
5192   Input Parameters:
5193 + dm        - The `DM`
5194 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5195 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5196 
5197   Output Parameter:
5198 . newdm - The `DM`
5199 
5200   Level: advanced
5201 
5202 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5203 @*/
DMCopyFields(DM dm,PetscInt minDegree,PetscInt maxDegree,DM newdm)5204 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5205 {
5206   PetscInt Nf, f;
5207 
5208   PetscFunctionBegin;
5209   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5210   PetscCall(DMGetNumFields(dm, &Nf));
5211   PetscCall(DMClearFields(newdm));
5212   for (f = 0; f < Nf; ++f) {
5213     DMLabel      label;
5214     PetscObject  field;
5215     PetscClassId id;
5216     PetscBool    useCone, useClosure;
5217 
5218     PetscCall(DMGetField(dm, f, &label, &field));
5219     PetscCall(PetscObjectGetClassId(field, &id));
5220     if (id == PETSCFE_CLASSID) {
5221       PetscFE newfe;
5222 
5223       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5224       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5225       PetscCall(PetscFEDestroy(&newfe));
5226     } else {
5227       PetscCall(DMSetField(newdm, f, label, field));
5228     }
5229     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5230     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5231   }
5232   // Create nullspace constructor slots
5233   if (dm->nullspaceConstructors) {
5234     PetscCall(PetscFree2(newdm->nullspaceConstructors, newdm->nearnullspaceConstructors));
5235     PetscCall(PetscCalloc2(Nf, &newdm->nullspaceConstructors, Nf, &newdm->nearnullspaceConstructors));
5236   }
5237   PetscFunctionReturn(PETSC_SUCCESS);
5238 }
5239 
5240 /*@
5241   DMGetAdjacency - Returns the flags for determining variable influence
5242 
5243   Not Collective
5244 
5245   Input Parameters:
5246 + dm - The `DM` object
5247 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5248 
5249   Output Parameters:
5250 + useCone    - Flag for variable influence starting with the cone operation
5251 - useClosure - Flag for variable influence using transitive closure
5252 
5253   Level: developer
5254 
5255   Notes:
5256 .vb
5257      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5258      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5259      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5260 .ve
5261   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5262 
5263 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5264 @*/
DMGetAdjacency(DM dm,PetscInt f,PetscBool * useCone,PetscBool * useClosure)5265 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5266 {
5267   PetscFunctionBegin;
5268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5269   if (useCone) PetscAssertPointer(useCone, 3);
5270   if (useClosure) PetscAssertPointer(useClosure, 4);
5271   if (f < 0) {
5272     if (useCone) *useCone = dm->adjacency[0];
5273     if (useClosure) *useClosure = dm->adjacency[1];
5274   } else {
5275     PetscInt Nf;
5276 
5277     PetscCall(DMGetNumFields(dm, &Nf));
5278     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5279     if (useCone) *useCone = dm->fields[f].adjacency[0];
5280     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5281   }
5282   PetscFunctionReturn(PETSC_SUCCESS);
5283 }
5284 
5285 /*@
5286   DMSetAdjacency - Set the flags for determining variable influence
5287 
5288   Not Collective
5289 
5290   Input Parameters:
5291 + dm         - The `DM` object
5292 . f          - The field number
5293 . useCone    - Flag for variable influence starting with the cone operation
5294 - useClosure - Flag for variable influence using transitive closure
5295 
5296   Level: developer
5297 
5298   Notes:
5299 .vb
5300      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5301      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5302      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5303 .ve
5304   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5305 
5306 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5307 @*/
DMSetAdjacency(DM dm,PetscInt f,PetscBool useCone,PetscBool useClosure)5308 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5309 {
5310   PetscFunctionBegin;
5311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5312   if (f < 0) {
5313     dm->adjacency[0] = useCone;
5314     dm->adjacency[1] = useClosure;
5315   } else {
5316     PetscInt Nf;
5317 
5318     PetscCall(DMGetNumFields(dm, &Nf));
5319     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5320     dm->fields[f].adjacency[0] = useCone;
5321     dm->fields[f].adjacency[1] = useClosure;
5322   }
5323   PetscFunctionReturn(PETSC_SUCCESS);
5324 }
5325 
5326 /*@
5327   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5328 
5329   Not collective
5330 
5331   Input Parameter:
5332 . dm - The `DM` object
5333 
5334   Output Parameters:
5335 + useCone    - Flag for variable influence starting with the cone operation
5336 - useClosure - Flag for variable influence using transitive closure
5337 
5338   Level: developer
5339 
5340   Notes:
5341 .vb
5342      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5343      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5344      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5345 .ve
5346 
5347 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5348 @*/
DMGetBasicAdjacency(DM dm,PetscBool * useCone,PetscBool * useClosure)5349 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5350 {
5351   PetscInt Nf;
5352 
5353   PetscFunctionBegin;
5354   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5355   if (useCone) PetscAssertPointer(useCone, 2);
5356   if (useClosure) PetscAssertPointer(useClosure, 3);
5357   PetscCall(DMGetNumFields(dm, &Nf));
5358   if (!Nf) {
5359     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5360   } else {
5361     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5362   }
5363   PetscFunctionReturn(PETSC_SUCCESS);
5364 }
5365 
5366 /*@
5367   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5368 
5369   Not Collective
5370 
5371   Input Parameters:
5372 + dm         - The `DM` object
5373 . useCone    - Flag for variable influence starting with the cone operation
5374 - useClosure - Flag for variable influence using transitive closure
5375 
5376   Level: developer
5377 
5378   Notes:
5379 .vb
5380      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5381      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5382      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5383 .ve
5384 
5385 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5386 @*/
DMSetBasicAdjacency(DM dm,PetscBool useCone,PetscBool useClosure)5387 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5388 {
5389   PetscInt Nf;
5390 
5391   PetscFunctionBegin;
5392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5393   PetscCall(DMGetNumFields(dm, &Nf));
5394   if (!Nf) {
5395     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5396   } else {
5397     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5398   }
5399   PetscFunctionReturn(PETSC_SUCCESS);
5400 }
5401 
DMCompleteBCLabels_Internal(DM dm)5402 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5403 {
5404   DM           plex;
5405   DMLabel     *labels, *glabels;
5406   const char **names;
5407   char        *sendNames, *recvNames;
5408   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5409   size_t       len;
5410   MPI_Comm     comm;
5411   PetscMPIInt  rank, size, p, *counts, *displs;
5412 
5413   PetscFunctionBegin;
5414   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5415   PetscCallMPI(MPI_Comm_size(comm, &size));
5416   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5417   PetscCall(DMGetNumDS(dm, &Nds));
5418   for (s = 0; s < Nds; ++s) {
5419     PetscDS  dsBC;
5420     PetscInt numBd;
5421 
5422     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5423     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5424     maxLabels += numBd;
5425   }
5426   PetscCall(PetscCalloc1(maxLabels, &labels));
5427   /* Get list of labels to be completed */
5428   for (s = 0; s < Nds; ++s) {
5429     PetscDS  dsBC;
5430     PetscInt numBd, bd;
5431 
5432     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5433     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5434     for (bd = 0; bd < numBd; ++bd) {
5435       DMLabel      label;
5436       PetscInt     field;
5437       PetscObject  obj;
5438       PetscClassId id;
5439 
5440       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5441       PetscCall(DMGetField(dm, field, NULL, &obj));
5442       PetscCall(PetscObjectGetClassId(obj, &id));
5443       if (id != PETSCFE_CLASSID || !label) continue;
5444       for (l = 0; l < Nl; ++l)
5445         if (labels[l] == label) break;
5446       if (l == Nl) labels[Nl++] = label;
5447     }
5448   }
5449   /* Get label names */
5450   PetscCall(PetscMalloc1(Nl, &names));
5451   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5452   for (l = 0; l < Nl; ++l) {
5453     PetscCall(PetscStrlen(names[l], &len));
5454     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5455   }
5456   PetscCall(PetscFree(labels));
5457   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5458   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5459   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5460   PetscCall(PetscFree(names));
5461   /* Put all names on all processes */
5462   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5463   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5464   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5465   gNl = displs[size];
5466   for (p = 0; p < size; ++p) {
5467     counts[p] *= gmaxLen;
5468     displs[p] *= gmaxLen;
5469   }
5470   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5471   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5472   PetscCall(PetscFree2(counts, displs));
5473   PetscCall(PetscFree(sendNames));
5474   for (l = 0, gl = 0; l < gNl; ++l) {
5475     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5476     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5477     for (m = 0; m < gl; ++m)
5478       if (glabels[m] == glabels[gl]) goto next_label;
5479     PetscCall(DMConvert(dm, DMPLEX, &plex));
5480     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5481     PetscCall(DMDestroy(&plex));
5482     ++gl;
5483   next_label:
5484     continue;
5485   }
5486   PetscCall(PetscFree2(recvNames, glabels));
5487   PetscFunctionReturn(PETSC_SUCCESS);
5488 }
5489 
DMDSEnlarge_Static(DM dm,PetscInt NdsNew)5490 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5491 {
5492   DMSpace *tmpd;
5493   PetscInt Nds = dm->Nds, s;
5494 
5495   PetscFunctionBegin;
5496   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5497   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5498   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5499   for (s = Nds; s < NdsNew; ++s) {
5500     tmpd[s].ds     = NULL;
5501     tmpd[s].label  = NULL;
5502     tmpd[s].fields = NULL;
5503   }
5504   PetscCall(PetscFree(dm->probs));
5505   dm->Nds   = NdsNew;
5506   dm->probs = tmpd;
5507   PetscFunctionReturn(PETSC_SUCCESS);
5508 }
5509 
5510 /*@
5511   DMGetNumDS - Get the number of discrete systems in the `DM`
5512 
5513   Not Collective
5514 
5515   Input Parameter:
5516 . dm - The `DM`
5517 
5518   Output Parameter:
5519 . Nds - The number of `PetscDS` objects
5520 
5521   Level: intermediate
5522 
5523 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5524 @*/
DMGetNumDS(DM dm,PetscInt * Nds)5525 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5526 {
5527   PetscFunctionBegin;
5528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5529   PetscAssertPointer(Nds, 2);
5530   *Nds = dm->Nds;
5531   PetscFunctionReturn(PETSC_SUCCESS);
5532 }
5533 
5534 /*@
5535   DMClearDS - Remove all discrete systems from the `DM`
5536 
5537   Logically Collective
5538 
5539   Input Parameter:
5540 . dm - The `DM`
5541 
5542   Level: intermediate
5543 
5544 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5545 @*/
DMClearDS(DM dm)5546 PetscErrorCode DMClearDS(DM dm)
5547 {
5548   PetscInt s;
5549 
5550   PetscFunctionBegin;
5551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5552   for (s = 0; s < dm->Nds; ++s) {
5553     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5554     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5555     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5556     PetscCall(ISDestroy(&dm->probs[s].fields));
5557   }
5558   PetscCall(PetscFree(dm->probs));
5559   dm->probs = NULL;
5560   dm->Nds   = 0;
5561   PetscFunctionReturn(PETSC_SUCCESS);
5562 }
5563 
5564 /*@
5565   DMGetDS - Get the default `PetscDS`
5566 
5567   Not Collective
5568 
5569   Input Parameter:
5570 . dm - The `DM`
5571 
5572   Output Parameter:
5573 . ds - The default `PetscDS`
5574 
5575   Level: intermediate
5576 
5577   Note:
5578   The `ds` is owned by the `dm` and should not be destroyed directly.
5579 
5580 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5581 @*/
DMGetDS(DM dm,PetscDS * ds)5582 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5583 {
5584   PetscFunctionBeginHot;
5585   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5586   PetscAssertPointer(ds, 2);
5587   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5588   *ds = dm->probs[0].ds;
5589   PetscFunctionReturn(PETSC_SUCCESS);
5590 }
5591 
5592 /*@
5593   DMGetCellDS - Get the `PetscDS` defined on a given cell
5594 
5595   Not Collective
5596 
5597   Input Parameters:
5598 + dm    - The `DM`
5599 - point - Cell for the `PetscDS`
5600 
5601   Output Parameters:
5602 + ds   - The `PetscDS` defined on the given cell
5603 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if the same ds
5604 
5605   Level: developer
5606 
5607 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5608 @*/
DMGetCellDS(DM dm,PetscInt point,PetscDS * ds,PetscDS * dsIn)5609 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5610 {
5611   PetscDS  dsDef = NULL;
5612   PetscInt s;
5613 
5614   PetscFunctionBeginHot;
5615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5616   if (ds) PetscAssertPointer(ds, 3);
5617   if (dsIn) PetscAssertPointer(dsIn, 4);
5618   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5619   if (ds) *ds = NULL;
5620   if (dsIn) *dsIn = NULL;
5621   for (s = 0; s < dm->Nds; ++s) {
5622     PetscInt val;
5623 
5624     if (!dm->probs[s].label) {
5625       dsDef = dm->probs[s].ds;
5626     } else {
5627       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5628       if (val >= 0) {
5629         if (ds) *ds = dm->probs[s].ds;
5630         if (dsIn) *dsIn = dm->probs[s].dsIn;
5631         break;
5632       }
5633     }
5634   }
5635   if (ds && !*ds) *ds = dsDef;
5636   PetscFunctionReturn(PETSC_SUCCESS);
5637 }
5638 
5639 /*@
5640   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5641 
5642   Not Collective
5643 
5644   Input Parameters:
5645 + dm    - The `DM`
5646 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5647 
5648   Output Parameters:
5649 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5650 . ds     - The `PetscDS` defined on the given region, or `NULL`
5651 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5652 
5653   Level: advanced
5654 
5655   Note:
5656   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5657   the `PetscDS` for the full domain (if present) is returned. Returns with
5658   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5659 
5660 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5661 @*/
DMGetRegionDS(DM dm,DMLabel label,IS * fields,PetscDS * ds,PetscDS * dsIn)5662 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5663 {
5664   PetscInt Nds = dm->Nds, s;
5665 
5666   PetscFunctionBegin;
5667   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5668   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5669   if (fields) {
5670     PetscAssertPointer(fields, 3);
5671     *fields = NULL;
5672   }
5673   if (ds) {
5674     PetscAssertPointer(ds, 4);
5675     *ds = NULL;
5676   }
5677   if (dsIn) {
5678     PetscAssertPointer(dsIn, 5);
5679     *dsIn = NULL;
5680   }
5681   for (s = 0; s < Nds; ++s) {
5682     if (dm->probs[s].label == label || !dm->probs[s].label) {
5683       if (fields) *fields = dm->probs[s].fields;
5684       if (ds) *ds = dm->probs[s].ds;
5685       if (dsIn) *dsIn = dm->probs[s].dsIn;
5686       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5687     }
5688   }
5689   PetscFunctionReturn(PETSC_SUCCESS);
5690 }
5691 
5692 /*@
5693   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5694 
5695   Collective
5696 
5697   Input Parameters:
5698 + dm     - The `DM`
5699 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5700 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5701 . ds     - The `PetscDS` defined on the given region
5702 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5703 
5704   Level: advanced
5705 
5706   Note:
5707   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5708   the fields argument is ignored.
5709 
5710 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5711 @*/
DMSetRegionDS(DM dm,DMLabel label,IS fields,PetscDS ds,PetscDS dsIn)5712 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5713 {
5714   PetscInt Nds = dm->Nds, s;
5715 
5716   PetscFunctionBegin;
5717   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5718   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5719   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5720   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5721   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5722   for (s = 0; s < Nds; ++s) {
5723     if (dm->probs[s].label == label) {
5724       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5725       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5726       dm->probs[s].ds   = ds;
5727       dm->probs[s].dsIn = dsIn;
5728       PetscFunctionReturn(PETSC_SUCCESS);
5729     }
5730   }
5731   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5732   PetscCall(PetscObjectReference((PetscObject)label));
5733   PetscCall(PetscObjectReference((PetscObject)fields));
5734   PetscCall(PetscObjectReference((PetscObject)ds));
5735   PetscCall(PetscObjectReference((PetscObject)dsIn));
5736   if (!label) {
5737     /* Put the NULL label at the front, so it is returned as the default */
5738     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5739     Nds = 0;
5740   }
5741   dm->probs[Nds].label  = label;
5742   dm->probs[Nds].fields = fields;
5743   dm->probs[Nds].ds     = ds;
5744   dm->probs[Nds].dsIn   = dsIn;
5745   PetscFunctionReturn(PETSC_SUCCESS);
5746 }
5747 
5748 /*@
5749   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5750 
5751   Not Collective
5752 
5753   Input Parameters:
5754 + dm  - The `DM`
5755 - num - The region number, in [0, Nds)
5756 
5757   Output Parameters:
5758 + label  - The region label, or `NULL`
5759 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5760 . ds     - The `PetscDS` defined on the given region, or `NULL`
5761 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5762 
5763   Level: advanced
5764 
5765 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5766 @*/
DMGetRegionNumDS(DM dm,PetscInt num,DMLabel * label,IS * fields,PetscDS * ds,PetscDS * dsIn)5767 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5768 {
5769   PetscInt Nds;
5770 
5771   PetscFunctionBegin;
5772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5773   PetscCall(DMGetNumDS(dm, &Nds));
5774   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5775   if (label) {
5776     PetscAssertPointer(label, 3);
5777     *label = dm->probs[num].label;
5778   }
5779   if (fields) {
5780     PetscAssertPointer(fields, 4);
5781     *fields = dm->probs[num].fields;
5782   }
5783   if (ds) {
5784     PetscAssertPointer(ds, 5);
5785     *ds = dm->probs[num].ds;
5786   }
5787   if (dsIn) {
5788     PetscAssertPointer(dsIn, 6);
5789     *dsIn = dm->probs[num].dsIn;
5790   }
5791   PetscFunctionReturn(PETSC_SUCCESS);
5792 }
5793 
5794 /*@
5795   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5796 
5797   Not Collective
5798 
5799   Input Parameters:
5800 + dm     - The `DM`
5801 . num    - The region number, in [0, Nds)
5802 . label  - The region label, or `NULL`
5803 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5804 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5805 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5806 
5807   Level: advanced
5808 
5809 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5810 @*/
DMSetRegionNumDS(DM dm,PetscInt num,DMLabel label,IS fields,PetscDS ds,PetscDS dsIn)5811 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5812 {
5813   PetscInt Nds;
5814 
5815   PetscFunctionBegin;
5816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5817   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5818   PetscCall(DMGetNumDS(dm, &Nds));
5819   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5820   PetscCall(PetscObjectReference((PetscObject)label));
5821   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5822   dm->probs[num].label = label;
5823   if (fields) {
5824     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5825     PetscCall(PetscObjectReference((PetscObject)fields));
5826     PetscCall(ISDestroy(&dm->probs[num].fields));
5827     dm->probs[num].fields = fields;
5828   }
5829   if (ds) {
5830     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5831     PetscCall(PetscObjectReference((PetscObject)ds));
5832     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5833     dm->probs[num].ds = ds;
5834   }
5835   if (dsIn) {
5836     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5837     PetscCall(PetscObjectReference((PetscObject)dsIn));
5838     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5839     dm->probs[num].dsIn = dsIn;
5840   }
5841   PetscFunctionReturn(PETSC_SUCCESS);
5842 }
5843 
5844 /*@
5845   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5846 
5847   Not Collective
5848 
5849   Input Parameters:
5850 + dm - The `DM`
5851 - ds - The `PetscDS` defined on the given region
5852 
5853   Output Parameter:
5854 . num - The region number, in [0, Nds), or -1 if not found
5855 
5856   Level: advanced
5857 
5858 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5859 @*/
DMFindRegionNum(DM dm,PetscDS ds,PetscInt * num)5860 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5861 {
5862   PetscInt Nds, n;
5863 
5864   PetscFunctionBegin;
5865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5866   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5867   PetscAssertPointer(num, 3);
5868   PetscCall(DMGetNumDS(dm, &Nds));
5869   for (n = 0; n < Nds; ++n)
5870     if (ds == dm->probs[n].ds) break;
5871   if (n >= Nds) *num = -1;
5872   else *num = n;
5873   PetscFunctionReturn(PETSC_SUCCESS);
5874 }
5875 
5876 /*@
5877   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5878 
5879   Not Collective
5880 
5881   Input Parameters:
5882 + dm     - The `DM`
5883 . Nc     - The number of components for the field
5884 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5885 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5886 
5887   Output Parameter:
5888 . fem - The `PetscFE`
5889 
5890   Level: intermediate
5891 
5892   Note:
5893   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5894 
5895 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5896 @*/
DMCreateFEDefault(DM dm,PetscInt Nc,const char prefix[],PetscInt qorder,PetscFE * fem)5897 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5898 {
5899   DMPolytopeType ct;
5900   PetscInt       dim, cStart;
5901 
5902   PetscFunctionBegin;
5903   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5904   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5905   if (prefix) PetscAssertPointer(prefix, 3);
5906   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5907   PetscAssertPointer(fem, 5);
5908   PetscCall(DMGetDimension(dm, &dim));
5909   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5910   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5911   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5912   PetscFunctionReturn(PETSC_SUCCESS);
5913 }
5914 
5915 /*@
5916   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5917 
5918   Collective
5919 
5920   Input Parameter:
5921 . dm - The `DM`
5922 
5923   Options Database Key:
5924 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5925 
5926   Level: intermediate
5927 
5928   Developer Note:
5929   The name of this function is wrong. Create functions always return the created object as one of the arguments.
5930 
5931 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5932 @*/
DMCreateDS(DM dm)5933 PetscErrorCode DMCreateDS(DM dm)
5934 {
5935   MPI_Comm  comm;
5936   PetscDS   dsDef;
5937   DMLabel  *labelSet;
5938   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5939   PetscBool doSetup = PETSC_TRUE, flg;
5940 
5941   PetscFunctionBegin;
5942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5943   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5944   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5945   PetscCall(DMGetCoordinateDim(dm, &dE));
5946   // Create nullspace constructor slots
5947   PetscCall(PetscFree2(dm->nullspaceConstructors, dm->nearnullspaceConstructors));
5948   PetscCall(PetscCalloc2(Nf, &dm->nullspaceConstructors, Nf, &dm->nearnullspaceConstructors));
5949   /* Determine how many regions we have */
5950   PetscCall(PetscMalloc1(Nf, &labelSet));
5951   Nl   = 0;
5952   Ndef = 0;
5953   for (f = 0; f < Nf; ++f) {
5954     DMLabel  label = dm->fields[f].label;
5955     PetscInt l;
5956 
5957 #ifdef PETSC_HAVE_LIBCEED
5958     /* Move CEED context to discretizations */
5959     {
5960       PetscClassId id;
5961 
5962       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5963       if (id == PETSCFE_CLASSID) {
5964         Ceed ceed;
5965 
5966         PetscCall(DMGetCeed(dm, &ceed));
5967         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5968       }
5969     }
5970 #endif
5971     if (!label) {
5972       ++Ndef;
5973       continue;
5974     }
5975     for (l = 0; l < Nl; ++l)
5976       if (label == labelSet[l]) break;
5977     if (l < Nl) continue;
5978     labelSet[Nl++] = label;
5979   }
5980   /* Create default DS if there are no labels to intersect with */
5981   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5982   if (!dsDef && Ndef && !Nl) {
5983     IS        fields;
5984     PetscInt *fld, nf;
5985 
5986     for (f = 0, nf = 0; f < Nf; ++f)
5987       if (!dm->fields[f].label) ++nf;
5988     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5989     PetscCall(PetscMalloc1(nf, &fld));
5990     for (f = 0, nf = 0; f < Nf; ++f)
5991       if (!dm->fields[f].label) fld[nf++] = f;
5992     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5993     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5994     PetscCall(ISSetType(fields, ISGENERAL));
5995     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5996 
5997     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5998     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5999     PetscCall(PetscDSDestroy(&dsDef));
6000     PetscCall(ISDestroy(&fields));
6001   }
6002   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
6003   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6004   /* Intersect labels with default fields */
6005   if (Ndef && Nl) {
6006     DM              plex;
6007     DMLabel         cellLabel;
6008     IS              fieldIS, allcellIS, defcellIS = NULL;
6009     PetscInt       *fields;
6010     const PetscInt *cells;
6011     PetscInt        depth, nf = 0, n, c;
6012 
6013     PetscCall(DMConvert(dm, DMPLEX, &plex));
6014     PetscCall(DMPlexGetDepth(plex, &depth));
6015     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
6016     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
6017     /* TODO This looks like it only works for one label */
6018     for (l = 0; l < Nl; ++l) {
6019       DMLabel label = labelSet[l];
6020       IS      pointIS;
6021 
6022       PetscCall(ISDestroy(&defcellIS));
6023       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
6024       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
6025       PetscCall(ISDestroy(&pointIS));
6026     }
6027     PetscCall(ISDestroy(&allcellIS));
6028 
6029     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
6030     PetscCall(ISGetLocalSize(defcellIS, &n));
6031     PetscCall(ISGetIndices(defcellIS, &cells));
6032     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
6033     PetscCall(ISRestoreIndices(defcellIS, &cells));
6034     PetscCall(ISDestroy(&defcellIS));
6035     PetscCall(DMPlexLabelComplete(plex, cellLabel));
6036 
6037     PetscCall(PetscMalloc1(Ndef, &fields));
6038     for (f = 0; f < Nf; ++f)
6039       if (!dm->fields[f].label) fields[nf++] = f;
6040     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
6041     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
6042     PetscCall(ISSetType(fieldIS, ISGENERAL));
6043     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
6044 
6045     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6046     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6047     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6048     PetscCall(DMLabelDestroy(&cellLabel));
6049     PetscCall(PetscDSDestroy(&dsDef));
6050     PetscCall(ISDestroy(&fieldIS));
6051     PetscCall(DMDestroy(&plex));
6052   }
6053   /* Create label DSes
6054      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6055   */
6056   /* TODO Should check that labels are disjoint */
6057   for (l = 0; l < Nl; ++l) {
6058     DMLabel   label = labelSet[l];
6059     PetscDS   ds, dsIn = NULL;
6060     IS        fields;
6061     PetscInt *fld, nf;
6062 
6063     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6064     for (f = 0, nf = 0; f < Nf; ++f)
6065       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6066     PetscCall(PetscMalloc1(nf, &fld));
6067     for (f = 0, nf = 0; f < Nf; ++f)
6068       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6069     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6070     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6071     PetscCall(ISSetType(fields, ISGENERAL));
6072     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6073     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6074     {
6075       DMPolytopeType ct;
6076       PetscInt       lStart, lEnd;
6077       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6078 
6079       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6080       if (lStart >= 0) {
6081         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6082         switch (ct) {
6083         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6084         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6085         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6086         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6087           isCohesiveLocal = PETSC_TRUE;
6088           break;
6089         default:
6090           break;
6091         }
6092       }
6093       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPI_C_BOOL, MPI_LOR, comm));
6094       if (isCohesive) {
6095         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6096         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6097       }
6098       for (f = 0, nf = 0; f < Nf; ++f) {
6099         if (label == dm->fields[f].label || !dm->fields[f].label) {
6100           if (label == dm->fields[f].label) {
6101             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6102             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6103             if (dsIn) {
6104               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6105               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6106             }
6107           }
6108           ++nf;
6109         }
6110       }
6111     }
6112     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6113     PetscCall(ISDestroy(&fields));
6114     PetscCall(PetscDSDestroy(&ds));
6115     PetscCall(PetscDSDestroy(&dsIn));
6116   }
6117   PetscCall(PetscFree(labelSet));
6118   /* Set fields in DSes */
6119   for (s = 0; s < dm->Nds; ++s) {
6120     PetscDS         ds     = dm->probs[s].ds;
6121     PetscDS         dsIn   = dm->probs[s].dsIn;
6122     IS              fields = dm->probs[s].fields;
6123     const PetscInt *fld;
6124     PetscInt        nf, dsnf;
6125     PetscBool       isCohesive;
6126 
6127     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6128     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6129     PetscCall(ISGetLocalSize(fields, &nf));
6130     PetscCall(ISGetIndices(fields, &fld));
6131     for (f = 0; f < nf; ++f) {
6132       PetscObject  disc = dm->fields[fld[f]].disc;
6133       PetscBool    isCohesiveField;
6134       PetscClassId id;
6135 
6136       /* Handle DS with no fields */
6137       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6138       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6139       if (isCohesive) {
6140         if (!isCohesiveField) {
6141           PetscObject bdDisc;
6142 
6143           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6144           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6145           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6146         } else {
6147           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6148           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6149         }
6150       } else {
6151         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6152       }
6153       /* We allow people to have placeholder fields and construct the Section by hand */
6154       PetscCall(PetscObjectGetClassId(disc, &id));
6155       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6156     }
6157     PetscCall(ISRestoreIndices(fields, &fld));
6158   }
6159   /* Allow k-jet tabulation */
6160   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6161   if (flg) {
6162     for (s = 0; s < dm->Nds; ++s) {
6163       PetscDS  ds   = dm->probs[s].ds;
6164       PetscDS  dsIn = dm->probs[s].dsIn;
6165       PetscInt Nf, f;
6166 
6167       PetscCall(PetscDSGetNumFields(ds, &Nf));
6168       for (f = 0; f < Nf; ++f) {
6169         PetscCall(PetscDSSetJetDegree(ds, f, k));
6170         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6171       }
6172     }
6173   }
6174   /* Setup DSes */
6175   if (doSetup) {
6176     for (s = 0; s < dm->Nds; ++s) {
6177       if (dm->setfromoptionscalled) {
6178         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6179         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6180       }
6181       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6182       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6183     }
6184   }
6185   PetscFunctionReturn(PETSC_SUCCESS);
6186 }
6187 
6188 /*@
6189   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6190 
6191   Input Parameters:
6192 + dm     - The DM
6193 - tensor - Flag for tensor order
6194 
6195   Level: developer
6196 
6197 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6198 @*/
DMUseTensorOrder(DM dm,PetscBool tensor)6199 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6200 {
6201   PetscInt  Nf;
6202   PetscBool reorder = PETSC_TRUE, isPlex;
6203 
6204   PetscFunctionBegin;
6205   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6206   PetscCall(DMGetNumFields(dm, &Nf));
6207   for (PetscInt f = 0; f < Nf; ++f) {
6208     PetscObject  obj;
6209     PetscClassId id;
6210 
6211     PetscCall(DMGetField(dm, f, NULL, &obj));
6212     PetscCall(PetscObjectGetClassId(obj, &id));
6213     if (id == PETSCFE_CLASSID) {
6214       PetscSpace sp;
6215       PetscBool  tensor;
6216 
6217       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6218       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6219       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6220     } else reorder = PETSC_FALSE;
6221   }
6222   if (tensor) {
6223     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6224   } else {
6225     PetscSection s;
6226 
6227     PetscCall(DMGetLocalSection(dm, &s));
6228     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6229   }
6230   PetscFunctionReturn(PETSC_SUCCESS);
6231 }
6232 
6233 /*@
6234   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6235 
6236   Collective
6237 
6238   Input Parameters:
6239 + dm   - The `DM`
6240 - time - The time
6241 
6242   Output Parameters:
6243 + u   - The vector will be filled with exact solution values, or `NULL`
6244 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6245 
6246   Level: developer
6247 
6248   Note:
6249   The user must call `PetscDSSetExactSolution()` before using this routine
6250 
6251 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6252 @*/
DMComputeExactSolution(DM dm,PetscReal time,Vec u,Vec u_t)6253 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6254 {
6255   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, PetscCtx ctx);
6256   void   **ectxs;
6257   Vec      locu, locu_t;
6258   PetscInt Nf, Nds, s;
6259 
6260   PetscFunctionBegin;
6261   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6262   if (u) {
6263     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6264     PetscCall(DMGetLocalVector(dm, &locu));
6265     PetscCall(VecSet(locu, 0.));
6266   }
6267   if (u_t) {
6268     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6269     PetscCall(DMGetLocalVector(dm, &locu_t));
6270     PetscCall(VecSet(locu_t, 0.));
6271   }
6272   PetscCall(DMGetNumFields(dm, &Nf));
6273   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6274   PetscCall(DMGetNumDS(dm, &Nds));
6275   for (s = 0; s < Nds; ++s) {
6276     PetscDS         ds;
6277     DMLabel         label;
6278     IS              fieldIS;
6279     const PetscInt *fields, id = 1;
6280     PetscInt        dsNf, f;
6281 
6282     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6283     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6284     PetscCall(ISGetIndices(fieldIS, &fields));
6285     PetscCall(PetscArrayzero(exacts, Nf));
6286     PetscCall(PetscArrayzero(ectxs, Nf));
6287     if (u) {
6288       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6289       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6290       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6291     }
6292     if (u_t) {
6293       PetscCall(PetscArrayzero(exacts, Nf));
6294       PetscCall(PetscArrayzero(ectxs, Nf));
6295       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6296       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6297       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6298     }
6299     PetscCall(ISRestoreIndices(fieldIS, &fields));
6300   }
6301   if (u) {
6302     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6303     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6304   }
6305   if (u_t) {
6306     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6307     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6308   }
6309   PetscCall(PetscFree2(exacts, ectxs));
6310   if (u) {
6311     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6312     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6313     PetscCall(DMRestoreLocalVector(dm, &locu));
6314   }
6315   if (u_t) {
6316     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6317     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6318     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6319   }
6320   PetscFunctionReturn(PETSC_SUCCESS);
6321 }
6322 
DMTransferDS_Internal(DM dm,DMLabel label,IS fields,PetscInt minDegree,PetscInt maxDegree,PetscDS ds,PetscDS dsIn)6323 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6324 {
6325   PetscDS dsNew, dsInNew = NULL;
6326 
6327   PetscFunctionBegin;
6328   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6329   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6330   if (dsIn) {
6331     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6332     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6333   }
6334   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6335   PetscCall(PetscDSDestroy(&dsNew));
6336   PetscCall(PetscDSDestroy(&dsInNew));
6337   PetscFunctionReturn(PETSC_SUCCESS);
6338 }
6339 
6340 /*@
6341   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6342 
6343   Collective
6344 
6345   Input Parameters:
6346 + dm        - The `DM`
6347 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6348 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6349 
6350   Output Parameter:
6351 . newdm - The `DM`
6352 
6353   Level: advanced
6354 
6355 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6356 @*/
DMCopyDS(DM dm,PetscInt minDegree,PetscInt maxDegree,DM newdm)6357 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6358 {
6359   PetscInt Nds, s;
6360 
6361   PetscFunctionBegin;
6362   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6363   PetscCall(DMGetNumDS(dm, &Nds));
6364   PetscCall(DMClearDS(newdm));
6365   for (s = 0; s < Nds; ++s) {
6366     DMLabel  label;
6367     IS       fields;
6368     PetscDS  ds, dsIn, newds;
6369     PetscInt Nbd, bd;
6370 
6371     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6372     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6373     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6374     /* Complete new labels in the new DS */
6375     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6376     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6377     for (bd = 0; bd < Nbd; ++bd) {
6378       PetscWeakForm wf;
6379       DMLabel       label;
6380       PetscInt      field;
6381 
6382       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6383       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6384     }
6385   }
6386   PetscCall(DMCompleteBCLabels_Internal(newdm));
6387   PetscFunctionReturn(PETSC_SUCCESS);
6388 }
6389 
6390 /*@
6391   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6392 
6393   Collective
6394 
6395   Input Parameter:
6396 . dm - The `DM`
6397 
6398   Output Parameter:
6399 . newdm - The `DM`
6400 
6401   Level: advanced
6402 
6403   Developer Note:
6404   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6405 
6406 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6407 @*/
DMCopyDisc(DM dm,DM newdm)6408 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6409 {
6410   PetscFunctionBegin;
6411   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6412   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6413   PetscFunctionReturn(PETSC_SUCCESS);
6414 }
6415 
6416 /*@
6417   DMGetDimension - Return the topological dimension of the `DM`
6418 
6419   Not Collective
6420 
6421   Input Parameter:
6422 . dm - The `DM`
6423 
6424   Output Parameter:
6425 . dim - The topological dimension
6426 
6427   Level: beginner
6428 
6429 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6430 @*/
DMGetDimension(DM dm,PetscInt * dim)6431 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6432 {
6433   PetscFunctionBegin;
6434   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6435   PetscAssertPointer(dim, 2);
6436   *dim = dm->dim;
6437   PetscFunctionReturn(PETSC_SUCCESS);
6438 }
6439 
6440 /*@
6441   DMSetDimension - Set the topological dimension of the `DM`
6442 
6443   Collective
6444 
6445   Input Parameters:
6446 + dm  - The `DM`
6447 - dim - The topological dimension
6448 
6449   Level: beginner
6450 
6451 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6452 @*/
DMSetDimension(DM dm,PetscInt dim)6453 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6454 {
6455   PetscDS  ds;
6456   PetscInt Nds, n;
6457 
6458   PetscFunctionBegin;
6459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6460   PetscValidLogicalCollectiveInt(dm, dim, 2);
6461   dm->dim = dim;
6462   if (dm->dim >= 0) {
6463     PetscCall(DMGetNumDS(dm, &Nds));
6464     for (n = 0; n < Nds; ++n) {
6465       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6466       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6467     }
6468   }
6469   PetscFunctionReturn(PETSC_SUCCESS);
6470 }
6471 
6472 /*@
6473   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6474 
6475   Collective
6476 
6477   Input Parameters:
6478 + dm  - the `DM`
6479 - dim - the dimension
6480 
6481   Output Parameters:
6482 + pStart - The first point of the given dimension
6483 - pEnd   - The first point following points of the given dimension
6484 
6485   Level: intermediate
6486 
6487   Note:
6488   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6489   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6490   then the interval is empty.
6491 
6492 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6493 @*/
DMGetDimPoints(DM dm,PetscInt dim,PetscInt * pStart,PetscInt * pEnd)6494 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6495 {
6496   PetscInt d;
6497 
6498   PetscFunctionBegin;
6499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6500   PetscCall(DMGetDimension(dm, &d));
6501   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6502   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6503   PetscFunctionReturn(PETSC_SUCCESS);
6504 }
6505 
6506 /*@
6507   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6508 
6509   Collective
6510 
6511   Input Parameter:
6512 . dm - The original `DM`
6513 
6514   Output Parameter:
6515 . odm - The `DM` which provides the layout for output
6516 
6517   Level: intermediate
6518 
6519   Note:
6520   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6521   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6522   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6523 
6524 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6525 @*/
DMGetOutputDM(DM dm,DM * odm)6526 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6527 {
6528   PetscSection section;
6529   IS           perm;
6530   PetscBool    hasConstraints, newDM, gnewDM;
6531   PetscInt     num_face_sfs = 0;
6532 
6533   PetscFunctionBegin;
6534   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6535   PetscAssertPointer(odm, 2);
6536   PetscCall(DMGetLocalSection(dm, &section));
6537   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6538   PetscCall(PetscSectionGetPermutation(section, &perm));
6539   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL));
6540   newDM = hasConstraints || perm || (num_face_sfs > 0) ? PETSC_TRUE : PETSC_FALSE;
6541   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6542   if (!gnewDM) {
6543     *odm = dm;
6544     PetscFunctionReturn(PETSC_SUCCESS);
6545   }
6546   if (!dm->dmBC) {
6547     PetscSection newSection, gsection;
6548     PetscSF      sf, sfNatural;
6549     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6550 
6551     PetscCall(DMClone(dm, &dm->dmBC));
6552     PetscCall(DMCopyDisc(dm, dm->dmBC));
6553     PetscCall(PetscSectionClone(section, &newSection));
6554     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6555     PetscCall(PetscSectionDestroy(&newSection));
6556     PetscCall(DMGetNaturalSF(dm, &sfNatural));
6557     PetscCall(DMSetNaturalSF(dm->dmBC, sfNatural));
6558     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6559     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6560     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6561     PetscCall(PetscSectionDestroy(&gsection));
6562   }
6563   *odm = dm->dmBC;
6564   PetscFunctionReturn(PETSC_SUCCESS);
6565 }
6566 
6567 /*@
6568   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6569 
6570   Input Parameter:
6571 . dm - The original `DM`
6572 
6573   Output Parameters:
6574 + num - The output sequence number
6575 - val - The output sequence value
6576 
6577   Level: intermediate
6578 
6579   Note:
6580   This is intended for output that should appear in sequence, for instance
6581   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6582 
6583   Developer Note:
6584   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6585   not directly related to the `DM`.
6586 
6587 .seealso: [](ch_dmbase), `DM`, `VecView()`
6588 @*/
DMGetOutputSequenceNumber(DM dm,PetscInt * num,PetscReal * val)6589 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6590 {
6591   PetscFunctionBegin;
6592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6593   if (num) {
6594     PetscAssertPointer(num, 2);
6595     *num = dm->outputSequenceNum;
6596   }
6597   if (val) {
6598     PetscAssertPointer(val, 3);
6599     *val = dm->outputSequenceVal;
6600   }
6601   PetscFunctionReturn(PETSC_SUCCESS);
6602 }
6603 
6604 /*@
6605   DMSetOutputSequenceNumber - Set the sequence number/value for output
6606 
6607   Input Parameters:
6608 + dm  - The original `DM`
6609 . num - The output sequence number
6610 - val - The output sequence value
6611 
6612   Level: intermediate
6613 
6614   Note:
6615   This is intended for output that should appear in sequence, for instance
6616   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6617 
6618 .seealso: [](ch_dmbase), `DM`, `VecView()`
6619 @*/
DMSetOutputSequenceNumber(DM dm,PetscInt num,PetscReal val)6620 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6621 {
6622   PetscFunctionBegin;
6623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6624   dm->outputSequenceNum = num;
6625   dm->outputSequenceVal = val;
6626   PetscFunctionReturn(PETSC_SUCCESS);
6627 }
6628 
6629 /*@
6630   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6631 
6632   Input Parameters:
6633 + dm     - The original `DM`
6634 . viewer - The `PetscViewer` to get it from
6635 . name   - The sequence name
6636 - num    - The output sequence number
6637 
6638   Output Parameter:
6639 . val - The output sequence value
6640 
6641   Level: intermediate
6642 
6643   Note:
6644   This is intended for output that should appear in sequence, for instance
6645   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6646 
6647   Developer Note:
6648   It is unclear at the user API level why a `DM` is needed as input
6649 
6650 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6651 @*/
DMOutputSequenceLoad(DM dm,PetscViewer viewer,const char name[],PetscInt num,PetscReal * val)6652 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6653 {
6654   PetscBool ishdf5;
6655 
6656   PetscFunctionBegin;
6657   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6658   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6659   PetscAssertPointer(name, 3);
6660   PetscAssertPointer(val, 5);
6661   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6662   PetscCheck(ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6663 #if defined(PETSC_HAVE_HDF5)
6664   PetscScalar value;
6665 
6666   PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6667   *val = PetscRealPart(value);
6668 #endif
6669   PetscFunctionReturn(PETSC_SUCCESS);
6670 }
6671 
6672 /*@
6673   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6674 
6675   Input Parameters:
6676 + dm     - The original `DM`
6677 . viewer - The `PetscViewer` to get it from
6678 - name   - The sequence name
6679 
6680   Output Parameter:
6681 . len - The length of the output sequence
6682 
6683   Level: intermediate
6684 
6685   Note:
6686   This is intended for output that should appear in sequence, for instance
6687   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6688 
6689   Developer Note:
6690   It is unclear at the user API level why a `DM` is needed as input
6691 
6692 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6693 @*/
DMGetOutputSequenceLength(DM dm,PetscViewer viewer,const char name[],PetscInt * len)6694 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6695 {
6696   PetscBool ishdf5;
6697 
6698   PetscFunctionBegin;
6699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6700   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6701   PetscAssertPointer(name, 3);
6702   PetscAssertPointer(len, 4);
6703   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6704   PetscCheck(ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6705 #if defined(PETSC_HAVE_HDF5)
6706   PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6707 #endif
6708   PetscFunctionReturn(PETSC_SUCCESS);
6709 }
6710 
6711 /*@
6712   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6713 
6714   Not Collective
6715 
6716   Input Parameter:
6717 . dm - The `DM`
6718 
6719   Output Parameter:
6720 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6721 
6722   Level: beginner
6723 
6724 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6725 @*/
DMGetUseNatural(DM dm,PetscBool * useNatural)6726 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6727 {
6728   PetscFunctionBegin;
6729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6730   PetscAssertPointer(useNatural, 2);
6731   *useNatural = dm->useNatural;
6732   PetscFunctionReturn(PETSC_SUCCESS);
6733 }
6734 
6735 /*@
6736   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6737 
6738   Collective
6739 
6740   Input Parameters:
6741 + dm         - The `DM`
6742 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6743 
6744   Level: beginner
6745 
6746   Note:
6747   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6748 
6749 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6750 @*/
DMSetUseNatural(DM dm,PetscBool useNatural)6751 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6752 {
6753   PetscFunctionBegin;
6754   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6755   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6756   dm->useNatural = useNatural;
6757   PetscFunctionReturn(PETSC_SUCCESS);
6758 }
6759 
6760 /*@
6761   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6762 
6763   Not Collective
6764 
6765   Input Parameters:
6766 + dm   - The `DM` object
6767 - name - The label name
6768 
6769   Level: intermediate
6770 
6771 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6772 @*/
DMCreateLabel(DM dm,const char name[])6773 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6774 {
6775   PetscBool flg;
6776   DMLabel   label;
6777 
6778   PetscFunctionBegin;
6779   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6780   PetscAssertPointer(name, 2);
6781   PetscCall(DMHasLabel(dm, name, &flg));
6782   if (!flg) {
6783     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6784     PetscCall(DMAddLabel(dm, label));
6785     PetscCall(DMLabelDestroy(&label));
6786   }
6787   PetscFunctionReturn(PETSC_SUCCESS);
6788 }
6789 
6790 /*@
6791   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6792 
6793   Not Collective
6794 
6795   Input Parameters:
6796 + dm   - The `DM` object
6797 . l    - The index for the label
6798 - name - The label name
6799 
6800   Level: intermediate
6801 
6802 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6803 @*/
DMCreateLabelAtIndex(DM dm,PetscInt l,const char name[])6804 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6805 {
6806   DMLabelLink orig, prev = NULL;
6807   DMLabel     label;
6808   PetscInt    Nl, m;
6809   PetscBool   flg, match;
6810   const char *lname;
6811 
6812   PetscFunctionBegin;
6813   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6814   PetscAssertPointer(name, 3);
6815   PetscCall(DMHasLabel(dm, name, &flg));
6816   if (!flg) {
6817     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6818     PetscCall(DMAddLabel(dm, label));
6819     PetscCall(DMLabelDestroy(&label));
6820   }
6821   PetscCall(DMGetNumLabels(dm, &Nl));
6822   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6823   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6824     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6825     PetscCall(PetscStrcmp(name, lname, &match));
6826     if (match) break;
6827   }
6828   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6829   if (!m) dm->labels = orig->next;
6830   else prev->next = orig->next;
6831   if (!l) {
6832     orig->next = dm->labels;
6833     dm->labels = orig;
6834   } else {
6835     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6836     orig->next = prev->next;
6837     prev->next = orig;
6838   }
6839   PetscFunctionReturn(PETSC_SUCCESS);
6840 }
6841 
6842 /*@
6843   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6844 
6845   Not Collective
6846 
6847   Input Parameters:
6848 + dm    - The `DM` object
6849 . name  - The label name
6850 - point - The mesh point
6851 
6852   Output Parameter:
6853 . value - The label value for this point, or -1 if the point is not in the label
6854 
6855   Level: beginner
6856 
6857 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6858 @*/
DMGetLabelValue(DM dm,const char name[],PetscInt point,PetscInt * value)6859 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6860 {
6861   DMLabel label;
6862 
6863   PetscFunctionBegin;
6864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6865   PetscAssertPointer(name, 2);
6866   PetscCall(DMGetLabel(dm, name, &label));
6867   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6868   PetscCall(DMLabelGetValue(label, point, value));
6869   PetscFunctionReturn(PETSC_SUCCESS);
6870 }
6871 
6872 /*@
6873   DMSetLabelValue - Add a point to a `DMLabel` with given value
6874 
6875   Not Collective
6876 
6877   Input Parameters:
6878 + dm    - The `DM` object
6879 . name  - The label name
6880 . point - The mesh point
6881 - value - The label value for this point
6882 
6883   Output Parameter:
6884 
6885   Level: beginner
6886 
6887 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6888 @*/
DMSetLabelValue(DM dm,const char name[],PetscInt point,PetscInt value)6889 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6890 {
6891   DMLabel label;
6892 
6893   PetscFunctionBegin;
6894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6895   PetscAssertPointer(name, 2);
6896   PetscCall(DMGetLabel(dm, name, &label));
6897   if (!label) {
6898     PetscCall(DMCreateLabel(dm, name));
6899     PetscCall(DMGetLabel(dm, name, &label));
6900   }
6901   PetscCall(DMLabelSetValue(label, point, value));
6902   PetscFunctionReturn(PETSC_SUCCESS);
6903 }
6904 
6905 /*@
6906   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6907 
6908   Not Collective
6909 
6910   Input Parameters:
6911 + dm    - The `DM` object
6912 . name  - The label name
6913 . point - The mesh point
6914 - value - The label value for this point
6915 
6916   Level: beginner
6917 
6918 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6919 @*/
DMClearLabelValue(DM dm,const char name[],PetscInt point,PetscInt value)6920 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6921 {
6922   DMLabel label;
6923 
6924   PetscFunctionBegin;
6925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6926   PetscAssertPointer(name, 2);
6927   PetscCall(DMGetLabel(dm, name, &label));
6928   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6929   PetscCall(DMLabelClearValue(label, point, value));
6930   PetscFunctionReturn(PETSC_SUCCESS);
6931 }
6932 
6933 /*@
6934   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6935 
6936   Not Collective
6937 
6938   Input Parameters:
6939 + dm   - The `DM` object
6940 - name - The label name
6941 
6942   Output Parameter:
6943 . size - The number of different integer ids, or 0 if the label does not exist
6944 
6945   Level: beginner
6946 
6947   Developer Note:
6948   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6949 
6950 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6951 @*/
DMGetLabelSize(DM dm,const char name[],PetscInt * size)6952 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6953 {
6954   DMLabel label;
6955 
6956   PetscFunctionBegin;
6957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6958   PetscAssertPointer(name, 2);
6959   PetscAssertPointer(size, 3);
6960   PetscCall(DMGetLabel(dm, name, &label));
6961   *size = 0;
6962   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6963   PetscCall(DMLabelGetNumValues(label, size));
6964   PetscFunctionReturn(PETSC_SUCCESS);
6965 }
6966 
6967 /*@
6968   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6969 
6970   Not Collective
6971 
6972   Input Parameters:
6973 + dm   - The `DM` object
6974 - name - The label name
6975 
6976   Output Parameter:
6977 . ids - The integer ids, or `NULL` if the label does not exist
6978 
6979   Level: beginner
6980 
6981 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6982 @*/
DMGetLabelIdIS(DM dm,const char name[],IS * ids)6983 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6984 {
6985   DMLabel label;
6986 
6987   PetscFunctionBegin;
6988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6989   PetscAssertPointer(name, 2);
6990   PetscAssertPointer(ids, 3);
6991   PetscCall(DMGetLabel(dm, name, &label));
6992   *ids = NULL;
6993   if (label) {
6994     PetscCall(DMLabelGetValueIS(label, ids));
6995   } else {
6996     /* returning an empty IS */
6997     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6998   }
6999   PetscFunctionReturn(PETSC_SUCCESS);
7000 }
7001 
7002 /*@
7003   DMGetStratumSize - Get the number of points in a label stratum
7004 
7005   Not Collective
7006 
7007   Input Parameters:
7008 + dm    - The `DM` object
7009 . name  - The label name of the stratum
7010 - value - The stratum value
7011 
7012   Output Parameter:
7013 . size - The number of points, also called the stratum size
7014 
7015   Level: beginner
7016 
7017 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
7018 @*/
DMGetStratumSize(DM dm,const char name[],PetscInt value,PetscInt * size)7019 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7020 {
7021   DMLabel label;
7022 
7023   PetscFunctionBegin;
7024   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7025   PetscAssertPointer(name, 2);
7026   PetscAssertPointer(size, 4);
7027   PetscCall(DMGetLabel(dm, name, &label));
7028   *size = 0;
7029   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7030   PetscCall(DMLabelGetStratumSize(label, value, size));
7031   PetscFunctionReturn(PETSC_SUCCESS);
7032 }
7033 
7034 /*@
7035   DMGetStratumIS - Get the points in a label stratum
7036 
7037   Not Collective
7038 
7039   Input Parameters:
7040 + dm    - The `DM` object
7041 . name  - The label name
7042 - value - The stratum value
7043 
7044   Output Parameter:
7045 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
7046 
7047   Level: beginner
7048 
7049 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7050 @*/
DMGetStratumIS(DM dm,const char name[],PetscInt value,IS * points)7051 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7052 {
7053   DMLabel label;
7054 
7055   PetscFunctionBegin;
7056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7057   PetscAssertPointer(name, 2);
7058   PetscAssertPointer(points, 4);
7059   PetscCall(DMGetLabel(dm, name, &label));
7060   *points = NULL;
7061   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7062   PetscCall(DMLabelGetStratumIS(label, value, points));
7063   PetscFunctionReturn(PETSC_SUCCESS);
7064 }
7065 
7066 /*@
7067   DMSetStratumIS - Set the points in a label stratum
7068 
7069   Not Collective
7070 
7071   Input Parameters:
7072 + dm     - The `DM` object
7073 . name   - The label name
7074 . value  - The stratum value
7075 - points - The stratum points
7076 
7077   Level: beginner
7078 
7079 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7080 @*/
DMSetStratumIS(DM dm,const char name[],PetscInt value,IS points)7081 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7082 {
7083   DMLabel label;
7084 
7085   PetscFunctionBegin;
7086   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7087   PetscAssertPointer(name, 2);
7088   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7089   PetscCall(DMGetLabel(dm, name, &label));
7090   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7091   PetscCall(DMLabelSetStratumIS(label, value, points));
7092   PetscFunctionReturn(PETSC_SUCCESS);
7093 }
7094 
7095 /*@
7096   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7097 
7098   Not Collective
7099 
7100   Input Parameters:
7101 + dm    - The `DM` object
7102 . name  - The label name
7103 - value - The label value for this point
7104 
7105   Output Parameter:
7106 
7107   Level: beginner
7108 
7109 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7110 @*/
DMClearLabelStratum(DM dm,const char name[],PetscInt value)7111 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7112 {
7113   DMLabel label;
7114 
7115   PetscFunctionBegin;
7116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7117   PetscAssertPointer(name, 2);
7118   PetscCall(DMGetLabel(dm, name, &label));
7119   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7120   PetscCall(DMLabelClearStratum(label, value));
7121   PetscFunctionReturn(PETSC_SUCCESS);
7122 }
7123 
7124 /*@
7125   DMGetNumLabels - Return the number of labels defined by on the `DM`
7126 
7127   Not Collective
7128 
7129   Input Parameter:
7130 . dm - The `DM` object
7131 
7132   Output Parameter:
7133 . numLabels - the number of Labels
7134 
7135   Level: intermediate
7136 
7137 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7138 @*/
DMGetNumLabels(DM dm,PetscInt * numLabels)7139 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7140 {
7141   DMLabelLink next = dm->labels;
7142   PetscInt    n    = 0;
7143 
7144   PetscFunctionBegin;
7145   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7146   PetscAssertPointer(numLabels, 2);
7147   while (next) {
7148     ++n;
7149     next = next->next;
7150   }
7151   *numLabels = n;
7152   PetscFunctionReturn(PETSC_SUCCESS);
7153 }
7154 
7155 /*@
7156   DMGetLabelName - Return the name of nth label
7157 
7158   Not Collective
7159 
7160   Input Parameters:
7161 + dm - The `DM` object
7162 - n  - the label number
7163 
7164   Output Parameter:
7165 . name - the label name
7166 
7167   Level: intermediate
7168 
7169   Developer Note:
7170   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7171 
7172 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7173 @*/
DMGetLabelName(DM dm,PetscInt n,const char * name[])7174 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7175 {
7176   DMLabelLink next = dm->labels;
7177   PetscInt    l    = 0;
7178 
7179   PetscFunctionBegin;
7180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7181   PetscAssertPointer(name, 3);
7182   while (next) {
7183     if (l == n) {
7184       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7185       PetscFunctionReturn(PETSC_SUCCESS);
7186     }
7187     ++l;
7188     next = next->next;
7189   }
7190   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7191 }
7192 
7193 /*@
7194   DMHasLabel - Determine whether the `DM` has a label of a given name
7195 
7196   Not Collective
7197 
7198   Input Parameters:
7199 + dm   - The `DM` object
7200 - name - The label name
7201 
7202   Output Parameter:
7203 . hasLabel - `PETSC_TRUE` if the label is present
7204 
7205   Level: intermediate
7206 
7207 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7208 @*/
DMHasLabel(DM dm,const char name[],PetscBool * hasLabel)7209 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7210 {
7211   DMLabelLink next = dm->labels;
7212   const char *lname;
7213 
7214   PetscFunctionBegin;
7215   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7216   PetscAssertPointer(name, 2);
7217   PetscAssertPointer(hasLabel, 3);
7218   *hasLabel = PETSC_FALSE;
7219   while (next) {
7220     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7221     PetscCall(PetscStrcmp(name, lname, hasLabel));
7222     if (*hasLabel) break;
7223     next = next->next;
7224   }
7225   PetscFunctionReturn(PETSC_SUCCESS);
7226 }
7227 
7228 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7229 /*@
7230   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7231 
7232   Not Collective
7233 
7234   Input Parameters:
7235 + dm   - The `DM` object
7236 - name - The label name
7237 
7238   Output Parameter:
7239 . label - The `DMLabel`, or `NULL` if the label is absent
7240 
7241   Default labels in a `DMPLEX`:
7242 + "depth"       - Holds the depth (co-dimension) of each mesh point
7243 . "celltype"    - Holds the topological type of each cell
7244 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7245 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7246 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7247 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7248 
7249   Level: intermediate
7250 
7251 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7252 @*/
DMGetLabel(DM dm,const char name[],DMLabel * label)7253 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7254 {
7255   DMLabelLink next = dm->labels;
7256   PetscBool   hasLabel;
7257   const char *lname;
7258 
7259   PetscFunctionBegin;
7260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7261   PetscAssertPointer(name, 2);
7262   PetscAssertPointer(label, 3);
7263   *label = NULL;
7264   while (next) {
7265     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7266     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7267     if (hasLabel) {
7268       *label = next->label;
7269       break;
7270     }
7271     next = next->next;
7272   }
7273   PetscFunctionReturn(PETSC_SUCCESS);
7274 }
7275 
7276 /*@
7277   DMGetLabelByNum - Return the nth label on a `DM`
7278 
7279   Not Collective
7280 
7281   Input Parameters:
7282 + dm - The `DM` object
7283 - n  - the label number
7284 
7285   Output Parameter:
7286 . label - the label
7287 
7288   Level: intermediate
7289 
7290 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7291 @*/
DMGetLabelByNum(DM dm,PetscInt n,DMLabel * label)7292 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7293 {
7294   DMLabelLink next = dm->labels;
7295   PetscInt    l    = 0;
7296 
7297   PetscFunctionBegin;
7298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7299   PetscAssertPointer(label, 3);
7300   while (next) {
7301     if (l == n) {
7302       *label = next->label;
7303       PetscFunctionReturn(PETSC_SUCCESS);
7304     }
7305     ++l;
7306     next = next->next;
7307   }
7308   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7309 }
7310 
7311 /*@
7312   DMAddLabel - Add the label to this `DM`
7313 
7314   Not Collective
7315 
7316   Input Parameters:
7317 + dm    - The `DM` object
7318 - label - The `DMLabel`
7319 
7320   Level: developer
7321 
7322 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7323 @*/
DMAddLabel(DM dm,DMLabel label)7324 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7325 {
7326   DMLabelLink l, *p, tmpLabel;
7327   PetscBool   hasLabel;
7328   const char *lname;
7329   PetscBool   flg;
7330 
7331   PetscFunctionBegin;
7332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7333   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7334   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7335   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7336   PetscCall(PetscCalloc1(1, &tmpLabel));
7337   tmpLabel->label  = label;
7338   tmpLabel->output = PETSC_TRUE;
7339   for (p = &dm->labels; (l = *p); p = &l->next) { }
7340   *p = tmpLabel;
7341   PetscCall(PetscObjectReference((PetscObject)label));
7342   PetscCall(PetscStrcmp(lname, "depth", &flg));
7343   if (flg) dm->depthLabel = label;
7344   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7345   if (flg) dm->celltypeLabel = label;
7346   PetscFunctionReturn(PETSC_SUCCESS);
7347 }
7348 
7349 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7350 /*@
7351   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7352 
7353   Not Collective
7354 
7355   Input Parameters:
7356 + dm    - The `DM` object
7357 - label - The `DMLabel`, having the same name, to substitute
7358 
7359   Default labels in a `DMPLEX`:
7360 + "depth"       - Holds the depth (co-dimension) of each mesh point
7361 . "celltype"    - Holds the topological type of each cell
7362 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7363 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7364 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7365 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7366 
7367   Level: intermediate
7368 
7369 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7370 @*/
DMSetLabel(DM dm,DMLabel label)7371 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7372 {
7373   DMLabelLink next = dm->labels;
7374   PetscBool   hasLabel, flg;
7375   const char *name, *lname;
7376 
7377   PetscFunctionBegin;
7378   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7379   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7380   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7381   while (next) {
7382     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7383     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7384     if (hasLabel) {
7385       PetscCall(PetscObjectReference((PetscObject)label));
7386       PetscCall(PetscStrcmp(lname, "depth", &flg));
7387       if (flg) dm->depthLabel = label;
7388       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7389       if (flg) dm->celltypeLabel = label;
7390       PetscCall(DMLabelDestroy(&next->label));
7391       next->label = label;
7392       break;
7393     }
7394     next = next->next;
7395   }
7396   PetscFunctionReturn(PETSC_SUCCESS);
7397 }
7398 
7399 /*@
7400   DMRemoveLabel - Remove the label given by name from this `DM`
7401 
7402   Not Collective
7403 
7404   Input Parameters:
7405 + dm   - The `DM` object
7406 - name - The label name
7407 
7408   Output Parameter:
7409 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7410           caller is responsible for calling `DMLabelDestroy()`.
7411 
7412   Level: developer
7413 
7414 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7415 @*/
DMRemoveLabel(DM dm,const char name[],DMLabel * label)7416 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7417 {
7418   DMLabelLink link, *pnext;
7419   PetscBool   hasLabel;
7420   const char *lname;
7421 
7422   PetscFunctionBegin;
7423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7424   PetscAssertPointer(name, 2);
7425   if (label) {
7426     PetscAssertPointer(label, 3);
7427     *label = NULL;
7428   }
7429   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7430     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7431     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7432     if (hasLabel) {
7433       *pnext = link->next; /* Remove from list */
7434       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7435       if (hasLabel) dm->depthLabel = NULL;
7436       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7437       if (hasLabel) dm->celltypeLabel = NULL;
7438       if (label) *label = link->label;
7439       else PetscCall(DMLabelDestroy(&link->label));
7440       PetscCall(PetscFree(link));
7441       break;
7442     }
7443   }
7444   PetscFunctionReturn(PETSC_SUCCESS);
7445 }
7446 
7447 /*@
7448   DMRemoveLabelBySelf - Remove the label from this `DM`
7449 
7450   Not Collective
7451 
7452   Input Parameters:
7453 + dm           - The `DM` object
7454 . label        - The `DMLabel` to be removed from the `DM`
7455 - failNotFound - Should it fail if the label is not found in the `DM`?
7456 
7457   Level: developer
7458 
7459   Note:
7460   Only exactly the same instance is removed if found, name match is ignored.
7461   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7462   *label nullified.
7463 
7464 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7465 @*/
DMRemoveLabelBySelf(DM dm,DMLabel * label,PetscBool failNotFound)7466 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7467 {
7468   DMLabelLink link, *pnext;
7469   PetscBool   hasLabel = PETSC_FALSE;
7470 
7471   PetscFunctionBegin;
7472   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7473   PetscAssertPointer(label, 2);
7474   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7475   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7476   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7477   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7478     if (*label == link->label) {
7479       hasLabel = PETSC_TRUE;
7480       *pnext   = link->next; /* Remove from list */
7481       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7482       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7483       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7484       PetscCall(DMLabelDestroy(&link->label));
7485       PetscCall(PetscFree(link));
7486       break;
7487     }
7488   }
7489   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7490   PetscFunctionReturn(PETSC_SUCCESS);
7491 }
7492 
7493 /*@
7494   DMGetLabelOutput - Get the output flag for a given label
7495 
7496   Not Collective
7497 
7498   Input Parameters:
7499 + dm   - The `DM` object
7500 - name - The label name
7501 
7502   Output Parameter:
7503 . output - The flag for output
7504 
7505   Level: developer
7506 
7507 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7508 @*/
DMGetLabelOutput(DM dm,const char name[],PetscBool * output)7509 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7510 {
7511   DMLabelLink next = dm->labels;
7512   const char *lname;
7513 
7514   PetscFunctionBegin;
7515   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7516   PetscAssertPointer(name, 2);
7517   PetscAssertPointer(output, 3);
7518   while (next) {
7519     PetscBool flg;
7520 
7521     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7522     PetscCall(PetscStrcmp(name, lname, &flg));
7523     if (flg) {
7524       *output = next->output;
7525       PetscFunctionReturn(PETSC_SUCCESS);
7526     }
7527     next = next->next;
7528   }
7529   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7530 }
7531 
7532 /*@
7533   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7534 
7535   Not Collective
7536 
7537   Input Parameters:
7538 + dm     - The `DM` object
7539 . name   - The label name
7540 - output - `PETSC_TRUE` to save the label to the viewer
7541 
7542   Level: developer
7543 
7544 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7545 @*/
DMSetLabelOutput(DM dm,const char name[],PetscBool output)7546 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7547 {
7548   DMLabelLink next = dm->labels;
7549   const char *lname;
7550 
7551   PetscFunctionBegin;
7552   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7553   PetscAssertPointer(name, 2);
7554   while (next) {
7555     PetscBool flg;
7556 
7557     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7558     PetscCall(PetscStrcmp(name, lname, &flg));
7559     if (flg) {
7560       next->output = output;
7561       PetscFunctionReturn(PETSC_SUCCESS);
7562     }
7563     next = next->next;
7564   }
7565   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7566 }
7567 
7568 /*@
7569   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7570 
7571   Collective
7572 
7573   Input Parameters:
7574 + dmA   - The `DM` object with initial labels
7575 . dmB   - The `DM` object to which labels are copied
7576 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7577 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7578 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7579 
7580   Level: intermediate
7581 
7582   Note:
7583   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7584 
7585 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7586 @*/
DMCopyLabels(DM dmA,DM dmB,PetscCopyMode mode,PetscBool all,DMCopyLabelsMode emode)7587 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7588 {
7589   DMLabel     label, labelNew, labelOld;
7590   const char *name;
7591   PetscBool   flg;
7592   DMLabelLink link;
7593 
7594   PetscFunctionBegin;
7595   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7596   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7597   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7598   PetscValidLogicalCollectiveBool(dmA, all, 4);
7599   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7600   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7601   for (link = dmA->labels; link; link = link->next) {
7602     label = link->label;
7603     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7604     if (!all) {
7605       PetscCall(PetscStrcmp(name, "depth", &flg));
7606       if (flg) continue;
7607       PetscCall(PetscStrcmp(name, "dim", &flg));
7608       if (flg) continue;
7609       PetscCall(PetscStrcmp(name, "celltype", &flg));
7610       if (flg) continue;
7611     }
7612     PetscCall(DMGetLabel(dmB, name, &labelOld));
7613     if (labelOld) {
7614       switch (emode) {
7615       case DM_COPY_LABELS_KEEP:
7616         continue;
7617       case DM_COPY_LABELS_REPLACE:
7618         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7619         break;
7620       case DM_COPY_LABELS_FAIL:
7621         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7622       default:
7623         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7624       }
7625     }
7626     if (mode == PETSC_COPY_VALUES) {
7627       PetscCall(DMLabelDuplicate(label, &labelNew));
7628     } else {
7629       labelNew = label;
7630     }
7631     PetscCall(DMAddLabel(dmB, labelNew));
7632     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7633   }
7634   PetscFunctionReturn(PETSC_SUCCESS);
7635 }
7636 
7637 /*@C
7638   DMCompareLabels - Compare labels between two `DM` objects
7639 
7640   Collective; No Fortran Support
7641 
7642   Input Parameters:
7643 + dm0 - First `DM` object
7644 - dm1 - Second `DM` object
7645 
7646   Output Parameters:
7647 + equal   - (Optional) Flag whether labels of `dm0` and `dm1` are the same
7648 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7649 
7650   Level: intermediate
7651 
7652   Notes:
7653   The output flag equal will be the same on all processes.
7654 
7655   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7656 
7657   Make sure to pass equal is `NULL` on all processes or none of them.
7658 
7659   The output message is set independently on each rank.
7660 
7661   message must be freed with `PetscFree()`
7662 
7663   If message is passed as `NULL` and a difference is found, the difference description is printed to `stderr` in synchronized manner.
7664 
7665   Make sure to pass message as `NULL` on all processes or no processes.
7666 
7667   Labels are matched by name. If the number of labels and their names are equal,
7668   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7669 
7670   Developer Note:
7671   Cannot automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7672 
7673 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7674 @*/
DMCompareLabels(DM dm0,DM dm1,PetscBool * equal,char * message[])7675 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char *message[]) PeNS
7676 {
7677   PetscInt    n, i;
7678   char        msg[PETSC_MAX_PATH_LEN] = "";
7679   PetscBool   eq;
7680   MPI_Comm    comm;
7681   PetscMPIInt rank;
7682 
7683   PetscFunctionBegin;
7684   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7685   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7686   PetscCheckSameComm(dm0, 1, dm1, 2);
7687   if (equal) PetscAssertPointer(equal, 3);
7688   if (message) PetscAssertPointer(message, 4);
7689   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7690   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7691   {
7692     PetscInt n1;
7693 
7694     PetscCall(DMGetNumLabels(dm0, &n));
7695     PetscCall(DMGetNumLabels(dm1, &n1));
7696     eq = (PetscBool)(n == n1);
7697     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7698     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
7699     if (!eq) goto finish;
7700   }
7701   for (i = 0; i < n; i++) {
7702     DMLabel     l0, l1;
7703     const char *name;
7704     char       *msgInner;
7705 
7706     /* Ignore label order */
7707     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7708     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7709     PetscCall(DMGetLabel(dm1, name, &l1));
7710     if (!l1) {
7711       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7712       eq = PETSC_FALSE;
7713       break;
7714     }
7715     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7716     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7717     PetscCall(PetscFree(msgInner));
7718     if (!eq) break;
7719   }
7720   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
7721 finish:
7722   /* If message output arg not set, print to stderr */
7723   if (message) {
7724     *message = NULL;
7725     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7726   } else {
7727     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7728     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7729   }
7730   /* If same output arg not ser and labels are not equal, throw error */
7731   if (equal) *equal = eq;
7732   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7733   PetscFunctionReturn(PETSC_SUCCESS);
7734 }
7735 
DMSetLabelValue_Fast(DM dm,DMLabel * label,const char name[],PetscInt point,PetscInt value)7736 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7737 {
7738   PetscFunctionBegin;
7739   PetscAssertPointer(label, 2);
7740   if (!*label) {
7741     PetscCall(DMCreateLabel(dm, name));
7742     PetscCall(DMGetLabel(dm, name, label));
7743   }
7744   PetscCall(DMLabelSetValue(*label, point, value));
7745   PetscFunctionReturn(PETSC_SUCCESS);
7746 }
7747 
7748 /*
7749   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7750   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7751   (label, id) pair in the DM.
7752 
7753   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7754   each label.
7755 */
DMUniversalLabelCreate(DM dm,DMUniversalLabel * universal)7756 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7757 {
7758   DMUniversalLabel ul;
7759   PetscBool       *active;
7760   PetscInt         pStart, pEnd, p, Nl, l, m;
7761 
7762   PetscFunctionBegin;
7763   PetscCall(PetscMalloc1(1, &ul));
7764   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7765   PetscCall(DMGetNumLabels(dm, &Nl));
7766   PetscCall(PetscCalloc1(Nl, &active));
7767   ul->Nl = 0;
7768   for (l = 0; l < Nl; ++l) {
7769     PetscBool   isdepth, iscelltype;
7770     const char *name;
7771 
7772     PetscCall(DMGetLabelName(dm, l, &name));
7773     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7774     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7775     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7776     if (active[l]) ++ul->Nl;
7777   }
7778   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7779   ul->Nv = 0;
7780   for (l = 0, m = 0; l < Nl; ++l) {
7781     DMLabel     label;
7782     PetscInt    nv;
7783     const char *name;
7784 
7785     if (!active[l]) continue;
7786     PetscCall(DMGetLabelName(dm, l, &name));
7787     PetscCall(DMGetLabelByNum(dm, l, &label));
7788     PetscCall(DMLabelGetNumValues(label, &nv));
7789     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7790     ul->indices[m] = l;
7791     ul->Nv += nv;
7792     ul->offsets[m + 1] = nv;
7793     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7794     ++m;
7795   }
7796   for (l = 1; l <= ul->Nl; ++l) {
7797     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7798     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7799   }
7800   for (l = 0; l < ul->Nl; ++l) {
7801     PetscInt b;
7802 
7803     ul->masks[l] = 0;
7804     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7805   }
7806   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7807   for (l = 0, m = 0; l < Nl; ++l) {
7808     DMLabel         label;
7809     IS              valueIS;
7810     const PetscInt *varr;
7811     PetscInt        nv, v;
7812 
7813     if (!active[l]) continue;
7814     PetscCall(DMGetLabelByNum(dm, l, &label));
7815     PetscCall(DMLabelGetNumValues(label, &nv));
7816     PetscCall(DMLabelGetValueIS(label, &valueIS));
7817     PetscCall(ISGetIndices(valueIS, &varr));
7818     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7819     PetscCall(ISRestoreIndices(valueIS, &varr));
7820     PetscCall(ISDestroy(&valueIS));
7821     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7822     ++m;
7823   }
7824   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7825   for (p = pStart; p < pEnd; ++p) {
7826     PetscInt  uval   = 0;
7827     PetscBool marked = PETSC_FALSE;
7828 
7829     for (l = 0, m = 0; l < Nl; ++l) {
7830       DMLabel  label;
7831       PetscInt val, defval, loc, nv;
7832 
7833       if (!active[l]) continue;
7834       PetscCall(DMGetLabelByNum(dm, l, &label));
7835       PetscCall(DMLabelGetValue(label, p, &val));
7836       PetscCall(DMLabelGetDefaultValue(label, &defval));
7837       if (val == defval) {
7838         ++m;
7839         continue;
7840       }
7841       nv     = ul->offsets[m + 1] - ul->offsets[m];
7842       marked = PETSC_TRUE;
7843       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7844       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7845       uval += (loc + 1) << ul->bits[m];
7846       ++m;
7847     }
7848     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7849   }
7850   PetscCall(PetscFree(active));
7851   *universal = ul;
7852   PetscFunctionReturn(PETSC_SUCCESS);
7853 }
7854 
DMUniversalLabelDestroy(DMUniversalLabel * universal)7855 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7856 {
7857   PetscInt l;
7858 
7859   PetscFunctionBegin;
7860   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7861   PetscCall(DMLabelDestroy(&(*universal)->label));
7862   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7863   PetscCall(PetscFree((*universal)->values));
7864   PetscCall(PetscFree(*universal));
7865   *universal = NULL;
7866   PetscFunctionReturn(PETSC_SUCCESS);
7867 }
7868 
DMUniversalLabelGetLabel(DMUniversalLabel ul,DMLabel * ulabel)7869 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7870 {
7871   PetscFunctionBegin;
7872   PetscAssertPointer(ulabel, 2);
7873   *ulabel = ul->label;
7874   PetscFunctionReturn(PETSC_SUCCESS);
7875 }
7876 
DMUniversalLabelCreateLabels(DMUniversalLabel ul,PetscBool preserveOrder,DM dm)7877 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7878 {
7879   PetscInt Nl = ul->Nl, l;
7880 
7881   PetscFunctionBegin;
7882   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7883   for (l = 0; l < Nl; ++l) {
7884     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7885     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7886   }
7887   if (preserveOrder) {
7888     for (l = 0; l < ul->Nl; ++l) {
7889       const char *name;
7890       PetscBool   match;
7891 
7892       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7893       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7894       PetscCheck(match, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %" PetscInt_FMT " name %s does not match new name %s", l, name, ul->names[l]);
7895     }
7896   }
7897   PetscFunctionReturn(PETSC_SUCCESS);
7898 }
7899 
DMUniversalLabelSetLabelValue(DMUniversalLabel ul,DM dm,PetscBool useIndex,PetscInt p,PetscInt value)7900 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7901 {
7902   PetscInt l;
7903 
7904   PetscFunctionBegin;
7905   for (l = 0; l < ul->Nl; ++l) {
7906     DMLabel  label;
7907     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7908 
7909     if (lval) {
7910       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7911       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7912       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7913     }
7914   }
7915   PetscFunctionReturn(PETSC_SUCCESS);
7916 }
7917 
7918 /*@
7919   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7920 
7921   Not Collective
7922 
7923   Input Parameter:
7924 . dm - The `DM` object
7925 
7926   Output Parameter:
7927 . cdm - The coarse `DM`
7928 
7929   Level: intermediate
7930 
7931 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7932 @*/
DMGetCoarseDM(DM dm,DM * cdm)7933 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7934 {
7935   PetscFunctionBegin;
7936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7937   PetscAssertPointer(cdm, 2);
7938   *cdm = dm->coarseMesh;
7939   PetscFunctionReturn(PETSC_SUCCESS);
7940 }
7941 
7942 /*@
7943   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7944 
7945   Input Parameters:
7946 + dm  - The `DM` object
7947 - cdm - The coarse `DM`
7948 
7949   Level: intermediate
7950 
7951   Note:
7952   Normally this is set automatically by `DMRefine()`
7953 
7954 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7955 @*/
DMSetCoarseDM(DM dm,DM cdm)7956 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7957 {
7958   PetscFunctionBegin;
7959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7960   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7961   if (dm == cdm) cdm = NULL;
7962   PetscCall(PetscObjectReference((PetscObject)cdm));
7963   PetscCall(DMDestroy(&dm->coarseMesh));
7964   dm->coarseMesh = cdm;
7965   PetscFunctionReturn(PETSC_SUCCESS);
7966 }
7967 
7968 /*@
7969   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7970 
7971   Input Parameter:
7972 . dm - The `DM` object
7973 
7974   Output Parameter:
7975 . fdm - The fine `DM`
7976 
7977   Level: intermediate
7978 
7979 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7980 @*/
DMGetFineDM(DM dm,DM * fdm)7981 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7982 {
7983   PetscFunctionBegin;
7984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7985   PetscAssertPointer(fdm, 2);
7986   *fdm = dm->fineMesh;
7987   PetscFunctionReturn(PETSC_SUCCESS);
7988 }
7989 
7990 /*@
7991   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7992 
7993   Input Parameters:
7994 + dm  - The `DM` object
7995 - fdm - The fine `DM`
7996 
7997   Level: developer
7998 
7999   Note:
8000   Normally this is set automatically by `DMCoarsen()`
8001 
8002 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
8003 @*/
DMSetFineDM(DM dm,DM fdm)8004 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8005 {
8006   PetscFunctionBegin;
8007   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8008   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8009   if (dm == fdm) fdm = NULL;
8010   PetscCall(PetscObjectReference((PetscObject)fdm));
8011   PetscCall(DMDestroy(&dm->fineMesh));
8012   dm->fineMesh = fdm;
8013   PetscFunctionReturn(PETSC_SUCCESS);
8014 }
8015 
8016 /*@C
8017   DMAddBoundary - Add a boundary condition, for a single field, to a model represented by a `DM`
8018 
8019   Collective
8020 
8021   Input Parameters:
8022 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
8023 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
8024 . name     - The BC name
8025 . label    - The label defining constrained points
8026 . Nv       - The number of `DMLabel` values for constrained points
8027 . values   - An array of values for constrained points
8028 . field    - The field to constrain
8029 . Nc       - The number of constrained field components (0 will constrain all components)
8030 . comps    - An array of constrained component numbers
8031 . bcFunc   - A pointwise function giving boundary values
8032 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or `NULL`
8033 - ctx      - An optional user context for bcFunc
8034 
8035   Output Parameter:
8036 . bd - (Optional) Boundary number
8037 
8038   Options Database Keys:
8039 + -bc_<boundary name> <num>      - Overrides the boundary ids
8040 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8041 
8042   Level: intermediate
8043 
8044   Notes:
8045   If the `DM` is of type `DMPLEX` and the field is of type `PetscFE`, then this function completes the label using `DMPlexLabelComplete()`.
8046 
8047   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
8048 .vb
8049  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8050 .ve
8051 
8052   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8053 
8054 .vb
8055   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8056               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8057               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8058               PetscReal time, const PetscReal x[], PetscScalar bcval[])
8059 .ve
8060 + dim - the spatial dimension
8061 . Nf - the number of fields
8062 . uOff - the offset into u[] and u_t[] for each field
8063 . uOff_x - the offset into u_x[] for each field
8064 . u - each field evaluated at the current point
8065 . u_t - the time derivative of each field evaluated at the current point
8066 . u_x - the gradient of each field evaluated at the current point
8067 . aOff - the offset into a[] and a_t[] for each auxiliary field
8068 . aOff_x - the offset into a_x[] for each auxiliary field
8069 . a - each auxiliary field evaluated at the current point
8070 . a_t - the time derivative of each auxiliary field evaluated at the current point
8071 . a_x - the gradient of auxiliary each field evaluated at the current point
8072 . t - current time
8073 . x - coordinates of the current point
8074 . numConstants - number of constant parameters
8075 . constants - constant parameters
8076 - bcval - output values at the current point
8077 
8078 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8079 @*/
DMAddBoundary(DM dm,DMBoundaryConditionType type,const char name[],DMLabel label,PetscInt Nv,const PetscInt values[],PetscInt field,PetscInt Nc,const PetscInt comps[],PetscVoidFn * bcFunc,PetscVoidFn * bcFunc_t,PetscCtx ctx,PetscInt * bd)8080 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], PetscVoidFn *bcFunc, PetscVoidFn *bcFunc_t, PetscCtx ctx, PetscInt *bd)
8081 {
8082   PetscDS ds;
8083 
8084   PetscFunctionBegin;
8085   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8086   PetscValidLogicalCollectiveEnum(dm, type, 2);
8087   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8088   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8089   PetscValidLogicalCollectiveInt(dm, field, 7);
8090   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8091   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8092   PetscCall(DMGetDS(dm, &ds));
8093   /* Complete label */
8094   if (label) {
8095     PetscObject  obj;
8096     PetscClassId id;
8097 
8098     PetscCall(DMGetField(dm, field, NULL, &obj));
8099     PetscCall(PetscObjectGetClassId(obj, &id));
8100     if (id == PETSCFE_CLASSID) {
8101       DM plex;
8102 
8103       PetscCall(DMConvert(dm, DMPLEX, &plex));
8104       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8105       PetscCall(DMDestroy(&plex));
8106     }
8107   }
8108   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8109   PetscFunctionReturn(PETSC_SUCCESS);
8110 }
8111 
8112 /* TODO Remove this since now the structures are the same */
DMPopulateBoundary(DM dm)8113 static PetscErrorCode DMPopulateBoundary(DM dm)
8114 {
8115   PetscDS     ds;
8116   DMBoundary *lastnext;
8117   DSBoundary  dsbound;
8118 
8119   PetscFunctionBegin;
8120   PetscCall(DMGetDS(dm, &ds));
8121   dsbound = ds->boundary;
8122   if (dm->boundary) {
8123     DMBoundary next = dm->boundary;
8124 
8125     /* quick check to see if the PetscDS has changed */
8126     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8127     /* the PetscDS has changed: tear down and rebuild */
8128     while (next) {
8129       DMBoundary b = next;
8130 
8131       next = b->next;
8132       PetscCall(PetscFree(b));
8133     }
8134     dm->boundary = NULL;
8135   }
8136 
8137   lastnext = &dm->boundary;
8138   while (dsbound) {
8139     DMBoundary dmbound;
8140 
8141     PetscCall(PetscNew(&dmbound));
8142     dmbound->dsboundary = dsbound;
8143     dmbound->label      = dsbound->label;
8144     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8145     *lastnext = dmbound;
8146     lastnext  = &dmbound->next;
8147     dsbound   = dsbound->next;
8148   }
8149   PetscFunctionReturn(PETSC_SUCCESS);
8150 }
8151 
8152 /* TODO: missing manual page */
DMIsBoundaryPoint(DM dm,PetscInt point,PetscBool * isBd)8153 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8154 {
8155   DMBoundary b;
8156 
8157   PetscFunctionBegin;
8158   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8159   PetscAssertPointer(isBd, 3);
8160   *isBd = PETSC_FALSE;
8161   PetscCall(DMPopulateBoundary(dm));
8162   b = dm->boundary;
8163   while (b && !*isBd) {
8164     DMLabel    label = b->label;
8165     DSBoundary dsb   = b->dsboundary;
8166     PetscInt   i;
8167 
8168     if (label) {
8169       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8170     }
8171     b = b->next;
8172   }
8173   PetscFunctionReturn(PETSC_SUCCESS);
8174 }
8175 
8176 /*@
8177   DMHasBound - Determine whether a bound condition was specified
8178 
8179   Logically collective
8180 
8181   Input Parameter:
8182 . dm - The `DM`, with a `PetscDS` that matches the problem being constrained
8183 
8184   Output Parameter:
8185 . hasBound - Flag indicating if a bound condition was specified
8186 
8187   Level: intermediate
8188 
8189 .seealso: [](ch_dmbase), `DM`, `DSAddBoundary()`, `PetscDSAddBoundary()`
8190 @*/
DMHasBound(DM dm,PetscBool * hasBound)8191 PetscErrorCode DMHasBound(DM dm, PetscBool *hasBound)
8192 {
8193   PetscDS  ds;
8194   PetscInt Nf, numBd;
8195 
8196   PetscFunctionBegin;
8197   *hasBound = PETSC_FALSE;
8198   PetscCall(DMGetDS(dm, &ds));
8199   PetscCall(PetscDSGetNumFields(ds, &Nf));
8200   for (PetscInt f = 0; f < Nf; ++f) {
8201     PetscSimplePointFn *lfunc, *ufunc;
8202 
8203     PetscCall(PetscDSGetLowerBound(ds, f, &lfunc, NULL));
8204     PetscCall(PetscDSGetUpperBound(ds, f, &ufunc, NULL));
8205     if (lfunc || ufunc) *hasBound = PETSC_TRUE;
8206   }
8207 
8208   PetscCall(PetscDSGetNumBoundary(ds, &numBd));
8209   PetscCall(PetscDSUpdateBoundaryLabels(ds, dm));
8210   for (PetscInt b = 0; b < numBd; ++b) {
8211     PetscWeakForm           wf;
8212     DMBoundaryConditionType type;
8213     const char             *name;
8214     DMLabel                 label;
8215     PetscInt                numids;
8216     const PetscInt         *ids;
8217     PetscInt                field, Nc;
8218     const PetscInt         *comps;
8219     PetscVoidFn            *bvfunc;
8220     void                   *ctx;
8221 
8222     PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
8223     if (type == DM_BC_LOWER_BOUND || type == DM_BC_UPPER_BOUND) *hasBound = PETSC_TRUE;
8224   }
8225   PetscFunctionReturn(PETSC_SUCCESS);
8226 }
8227 
8228 /*@C
8229   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8230 
8231   Collective
8232 
8233   Input Parameters:
8234 + dm    - The `DM`
8235 . time  - The time
8236 . funcs - The coordinate functions to evaluate, one per field
8237 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8238 - mode  - The insertion mode for values
8239 
8240   Output Parameter:
8241 . X - vector
8242 
8243   Calling sequence of `funcs`:
8244 + dim  - The spatial dimension
8245 . time - The time at which to sample
8246 . x    - The coordinates
8247 . Nc   - The number of components
8248 . u    - The output field values
8249 - ctx  - optional user-defined function context
8250 
8251   Level: developer
8252 
8253   Developer Notes:
8254   This API is specific to only particular usage of `DM`
8255 
8256   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8257 
8258 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8259 @*/
DMProjectFunction(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec X)8260 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec X)
8261 {
8262   Vec localX;
8263 
8264   PetscFunctionBegin;
8265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8266   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8267   PetscCall(DMGetLocalVector(dm, &localX));
8268   PetscCall(VecSet(localX, 0.));
8269   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8270   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8271   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8272   PetscCall(DMRestoreLocalVector(dm, &localX));
8273   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8274   PetscFunctionReturn(PETSC_SUCCESS);
8275 }
8276 
8277 /*@C
8278   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8279 
8280   Not Collective
8281 
8282   Input Parameters:
8283 + dm    - The `DM`
8284 . time  - The time
8285 . funcs - The coordinate functions to evaluate, one per field
8286 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8287 - mode  - The insertion mode for values
8288 
8289   Output Parameter:
8290 . localX - vector
8291 
8292   Calling sequence of `funcs`:
8293 + dim  - The spatial dimension
8294 . time - The current timestep
8295 . x    - The coordinates
8296 . Nc   - The number of components
8297 . u    - The output field values
8298 - ctx  - optional user-defined function context
8299 
8300   Level: developer
8301 
8302   Developer Notes:
8303   This API is specific to only particular usage of `DM`
8304 
8305   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8306 
8307 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8308 @*/
DMProjectFunctionLocal(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec localX)8309 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec localX)
8310 {
8311   PetscFunctionBegin;
8312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8313   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8314   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8315   PetscFunctionReturn(PETSC_SUCCESS);
8316 }
8317 
8318 /*@C
8319   DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.
8320 
8321   Collective
8322 
8323   Input Parameters:
8324 + dm     - The `DM`
8325 . time   - The time
8326 . numIds - The number of ids
8327 . ids    - The ids
8328 . Nc     - The number of components
8329 . comps  - The components
8330 . label  - The `DMLabel` selecting the portion of the mesh for projection
8331 . funcs  - The coordinate functions to evaluate, one per field
8332 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8333 - mode   - The insertion mode for values
8334 
8335   Output Parameter:
8336 . X - vector
8337 
8338   Calling sequence of `funcs`:
8339 + dim  - The spatial dimension
8340 . time - The current timestep
8341 . x    - The coordinates
8342 . Nc   - The number of components
8343 . u    - The output field values
8344 - ctx  - optional user-defined function context
8345 
8346   Level: developer
8347 
8348   Developer Notes:
8349   This API is specific to only particular usage of `DM`
8350 
8351   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8352 
8353 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8354 @*/
DMProjectFunctionLabel(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec X)8355 PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec X)
8356 {
8357   Vec localX;
8358 
8359   PetscFunctionBegin;
8360   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8361   PetscCall(DMGetLocalVector(dm, &localX));
8362   PetscCall(VecSet(localX, 0.));
8363   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8364   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8365   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8366   PetscCall(DMRestoreLocalVector(dm, &localX));
8367   PetscFunctionReturn(PETSC_SUCCESS);
8368 }
8369 
8370 /*@C
8371   DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.
8372 
8373   Not Collective
8374 
8375   Input Parameters:
8376 + dm     - The `DM`
8377 . time   - The time
8378 . label  - The `DMLabel` selecting the portion of the mesh for projection
8379 . numIds - The number of ids
8380 . ids    - The ids
8381 . Nc     - The number of components
8382 . comps  - The components
8383 . funcs  - The coordinate functions to evaluate, one per field
8384 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8385 - mode   - The insertion mode for values
8386 
8387   Output Parameter:
8388 . localX - vector
8389 
8390   Calling sequence of `funcs`:
8391 + dim  - The spatial dimension
8392 . time - The current time
8393 . x    - The coordinates
8394 . Nc   - The number of components
8395 . u    - The output field values
8396 - ctx  - optional user-defined function context
8397 
8398   Level: developer
8399 
8400   Developer Notes:
8401   This API is specific to only particular usage of `DM`
8402 
8403   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8404 
8405 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8406 @*/
DMProjectFunctionLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec localX)8407 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec localX)
8408 {
8409   PetscFunctionBegin;
8410   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8411   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8412   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8413   PetscFunctionReturn(PETSC_SUCCESS);
8414 }
8415 
8416 /*@C
8417   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.
8418 
8419   Not Collective
8420 
8421   Input Parameters:
8422 + dm     - The `DM`
8423 . time   - The time
8424 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8425 . funcs  - The functions to evaluate, one per field
8426 - mode   - The insertion mode for values
8427 
8428   Output Parameter:
8429 . localX - The output vector
8430 
8431   Calling sequence of `funcs`:
8432 + dim          - The spatial dimension
8433 . Nf           - The number of input fields
8434 . NfAux        - The number of input auxiliary fields
8435 . uOff         - The offset of each field in u[]
8436 . uOff_x       - The offset of each field in u_x[]
8437 . u            - The field values at this point in space
8438 . u_t          - The field time derivative at this point in space (or `NULL`)
8439 . u_x          - The field derivatives at this point in space
8440 . aOff         - The offset of each auxiliary field in u[]
8441 . aOff_x       - The offset of each auxiliary field in u_x[]
8442 . a            - The auxiliary field values at this point in space
8443 . a_t          - The auxiliary field time derivative at this point in space (or `NULL`)
8444 . a_x          - The auxiliary field derivatives at this point in space
8445 . t            - The current time
8446 . x            - The coordinates of this point
8447 . numConstants - The number of constants
8448 . constants    - The value of each constant
8449 - f            - The value of the function at this point in space
8450 
8451   Level: intermediate
8452 
8453   Note:
8454   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8455   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8456   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8457   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8458 
8459   Developer Notes:
8460   This API is specific to only particular usage of `DM`
8461 
8462   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8463 
8464 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8465 `DMProjectFunction()`, `DMComputeL2Diff()`
8466 @*/
DMProjectFieldLocal(DM dm,PetscReal time,Vec localU,void (** funcs)(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[]),InsertMode mode,Vec localX)8467 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(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[]), InsertMode mode, Vec localX)
8468 {
8469   PetscFunctionBegin;
8470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8471   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8472   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8473   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8474   PetscFunctionReturn(PETSC_SUCCESS);
8475 }
8476 
8477 /*@C
8478   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.
8479 
8480   Not Collective
8481 
8482   Input Parameters:
8483 + dm     - The `DM`
8484 . time   - The time
8485 . label  - The `DMLabel` marking the portion of the domain to output
8486 . numIds - The number of label ids to use
8487 . ids    - The label ids to use for marking
8488 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8489 . comps  - The components to set in the output, or `NULL` for all components
8490 . localU - The input field vector
8491 . funcs  - The functions to evaluate, one per field
8492 - mode   - The insertion mode for values
8493 
8494   Output Parameter:
8495 . localX - The output vector
8496 
8497   Calling sequence of `funcs`:
8498 + dim          - The spatial dimension
8499 . Nf           - The number of input fields
8500 . NfAux        - The number of input auxiliary fields
8501 . uOff         - The offset of each field in u[]
8502 . uOff_x       - The offset of each field in u_x[]
8503 . u            - The field values at this point in space
8504 . u_t          - The field time derivative at this point in space (or `NULL`)
8505 . u_x          - The field derivatives at this point in space
8506 . aOff         - The offset of each auxiliary field in u[]
8507 . aOff_x       - The offset of each auxiliary field in u_x[]
8508 . a            - The auxiliary field values at this point in space
8509 . a_t          - The auxiliary field time derivative at this point in space (or `NULL`)
8510 . a_x          - The auxiliary field derivatives at this point in space
8511 . t            - The current time
8512 . x            - The coordinates of this point
8513 . numConstants - The number of constants
8514 . constants    - The value of each constant
8515 - f            - The value of the function at this point in space
8516 
8517   Level: intermediate
8518 
8519   Note:
8520   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8521   The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8522   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8523   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8524 
8525   Developer Notes:
8526   This API is specific to only particular usage of `DM`
8527 
8528   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8529 
8530 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8531 @*/
DMProjectFieldLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec localU,void (** funcs)(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[]),InsertMode mode,Vec localX)8532 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(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[]), InsertMode mode, Vec localX)
8533 {
8534   PetscFunctionBegin;
8535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8536   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8537   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8538   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8539   PetscFunctionReturn(PETSC_SUCCESS);
8540 }
8541 
8542 /*@C
8543   DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.
8544 
8545   Not Collective
8546 
8547   Input Parameters:
8548 + dm     - The `DM`
8549 . time   - The time
8550 . label  - The `DMLabel` marking the portion of the domain to output
8551 . numIds - The number of label ids to use
8552 . ids    - The label ids to use for marking
8553 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8554 . comps  - The components to set in the output, or `NULL` for all components
8555 . U      - The input field vector
8556 . funcs  - The functions to evaluate, one per field
8557 - mode   - The insertion mode for values
8558 
8559   Output Parameter:
8560 . X - The output vector
8561 
8562   Calling sequence of `funcs`:
8563 + dim          - The spatial dimension
8564 . Nf           - The number of input fields
8565 . NfAux        - The number of input auxiliary fields
8566 . uOff         - The offset of each field in u[]
8567 . uOff_x       - The offset of each field in u_x[]
8568 . u            - The field values at this point in space
8569 . u_t          - The field time derivative at this point in space (or `NULL`)
8570 . u_x          - The field derivatives at this point in space
8571 . aOff         - The offset of each auxiliary field in u[]
8572 . aOff_x       - The offset of each auxiliary field in u_x[]
8573 . a            - The auxiliary field values at this point in space
8574 . a_t          - The auxiliary field time derivative at this point in space (or `NULL`)
8575 . a_x          - The auxiliary field derivatives at this point in space
8576 . t            - The current time
8577 . x            - The coordinates of this point
8578 . numConstants - The number of constants
8579 . constants    - The value of each constant
8580 - f            - The value of the function at this point in space
8581 
8582   Level: intermediate
8583 
8584   Note:
8585   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8586   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8587   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8588   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8589 
8590   Developer Notes:
8591   This API is specific to only particular usage of `DM`
8592 
8593   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8594 
8595 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8596 @*/
DMProjectFieldLabel(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec U,void (** funcs)(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[]),InsertMode mode,Vec X)8597 PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(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[]), InsertMode mode, Vec X)
8598 {
8599   DM  dmIn;
8600   Vec localU, localX;
8601 
8602   PetscFunctionBegin;
8603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8604   PetscCall(VecGetDM(U, &dmIn));
8605   PetscCall(DMGetLocalVector(dmIn, &localU));
8606   PetscCall(DMGetLocalVector(dm, &localX));
8607   PetscCall(VecSet(localX, 0.));
8608   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8609   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8610   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8611   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8612   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8613   PetscCall(DMRestoreLocalVector(dm, &localX));
8614   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8615   PetscFunctionReturn(PETSC_SUCCESS);
8616 }
8617 
8618 /*@C
8619   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.
8620 
8621   Not Collective
8622 
8623   Input Parameters:
8624 + dm     - The `DM`
8625 . time   - The time
8626 . label  - The `DMLabel` marking the portion of the domain boundary to output
8627 . numIds - The number of label ids to use
8628 . ids    - The label ids to use for marking
8629 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8630 . comps  - The components to set in the output, or `NULL` for all components
8631 . localU - The input field vector
8632 . funcs  - The functions to evaluate, one per field
8633 - mode   - The insertion mode for values
8634 
8635   Output Parameter:
8636 . localX - The output vector
8637 
8638   Calling sequence of `funcs`:
8639 + dim          - The spatial dimension
8640 . Nf           - The number of input fields
8641 . NfAux        - The number of input auxiliary fields
8642 . uOff         - The offset of each field in u[]
8643 . uOff_x       - The offset of each field in u_x[]
8644 . u            - The field values at this point in space
8645 . u_t          - The field time derivative at this point in space (or `NULL`)
8646 . u_x          - The field derivatives at this point in space
8647 . aOff         - The offset of each auxiliary field in u[]
8648 . aOff_x       - The offset of each auxiliary field in u_x[]
8649 . a            - The auxiliary field values at this point in space
8650 . a_t          - The auxiliary field time derivative at this point in space (or `NULL`)
8651 . a_x          - The auxiliary field derivatives at this point in space
8652 . t            - The current time
8653 . x            - The coordinates of this point
8654 . n            - The face normal
8655 . numConstants - The number of constants
8656 . constants    - The value of each constant
8657 - f            - The value of the function at this point in space
8658 
8659   Level: intermediate
8660 
8661   Note:
8662   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8663   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8664   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8665   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8666 
8667   Developer Notes:
8668   This API is specific to only particular usage of `DM`
8669 
8670   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8671 
8672 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8673 @*/
DMProjectBdFieldLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec localU,void (** funcs)(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[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[]),InsertMode mode,Vec localX)8674 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(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[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8675 {
8676   PetscFunctionBegin;
8677   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8678   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8679   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8680   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8681   PetscFunctionReturn(PETSC_SUCCESS);
8682 }
8683 
8684 /*@C
8685   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8686 
8687   Collective
8688 
8689   Input Parameters:
8690 + dm    - The `DM`
8691 . time  - The time
8692 . funcs - The functions to evaluate for each field component
8693 . ctxs  - Optional array of contexts to pass to each function, or `NULL`.
8694 - X     - The coefficient vector u_h, a global vector
8695 
8696   Output Parameter:
8697 . diff - The diff ||u - u_h||_2
8698 
8699   Level: developer
8700 
8701   Developer Notes:
8702   This API is specific to only particular usage of `DM`
8703 
8704   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8705 
8706 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8707 @*/
DMComputeL2Diff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal * diff)8708 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8709 {
8710   PetscFunctionBegin;
8711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8712   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8713   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8714   PetscFunctionReturn(PETSC_SUCCESS);
8715 }
8716 
8717 /*@C
8718   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8719 
8720   Collective
8721 
8722   Input Parameters:
8723 + dm    - The `DM`
8724 . time  - The time
8725 . funcs - The gradient functions to evaluate for each field component
8726 . ctxs  - Optional array of contexts to pass to each function, or `NULL`.
8727 . X     - The coefficient vector u_h, a global vector
8728 - n     - The vector to project along
8729 
8730   Output Parameter:
8731 . diff - The diff ||(grad u - grad u_h) . n||_2
8732 
8733   Level: developer
8734 
8735   Developer Notes:
8736   This API is specific to only particular usage of `DM`
8737 
8738   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8739 
8740 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8741 @*/
DMComputeL2GradientDiff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,const PetscReal n[],PetscReal * diff)8742 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
8743 {
8744   PetscFunctionBegin;
8745   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8746   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8747   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8748   PetscFunctionReturn(PETSC_SUCCESS);
8749 }
8750 
8751 /*@C
8752   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8753 
8754   Collective
8755 
8756   Input Parameters:
8757 + dm    - The `DM`
8758 . time  - The time
8759 . funcs - The functions to evaluate for each field component
8760 . ctxs  - Optional array of contexts to pass to each function, or `NULL`.
8761 - X     - The coefficient vector u_h, a global vector
8762 
8763   Output Parameter:
8764 . diff - The array of differences, ||u^f - u^f_h||_2
8765 
8766   Level: developer
8767 
8768   Developer Notes:
8769   This API is specific to only particular usage of `DM`
8770 
8771   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8772 
8773 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8774 @*/
DMComputeL2FieldDiff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal diff[])8775 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8776 {
8777   PetscFunctionBegin;
8778   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8779   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8780   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8781   PetscFunctionReturn(PETSC_SUCCESS);
8782 }
8783 
8784 /*@C
8785   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8786 
8787   Not Collective
8788 
8789   Input Parameter:
8790 . dm - The `DM`
8791 
8792   Output Parameters:
8793 + nranks - the number of neighbours
8794 - ranks  - the neighbors ranks
8795 
8796   Level: beginner
8797 
8798   Note:
8799   Do not free the array, it is freed when the `DM` is destroyed.
8800 
8801 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8802 @*/
DMGetNeighbors(DM dm,PetscInt * nranks,const PetscMPIInt * ranks[])8803 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8804 {
8805   PetscFunctionBegin;
8806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8807   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8808   PetscFunctionReturn(PETSC_SUCCESS);
8809 }
8810 
8811 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8812 
8813 /*
8814     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8815     This must be a different function because it requires DM which is not defined in the Mat library
8816 */
MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void * sctx)8817 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8818 {
8819   PetscFunctionBegin;
8820   if (coloring->ctype == IS_COLORING_LOCAL) {
8821     Vec x1local;
8822     DM  dm;
8823     PetscCall(MatGetDM(J, &dm));
8824     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8825     PetscCall(DMGetLocalVector(dm, &x1local));
8826     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8827     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8828     x1 = x1local;
8829   }
8830   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8831   if (coloring->ctype == IS_COLORING_LOCAL) {
8832     DM dm;
8833     PetscCall(MatGetDM(J, &dm));
8834     PetscCall(DMRestoreLocalVector(dm, &x1));
8835   }
8836   PetscFunctionReturn(PETSC_SUCCESS);
8837 }
8838 
8839 /*@
8840   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8841 
8842   Input Parameters:
8843 + coloring   - The matrix to get the `DM` from
8844 - fdcoloring - the `MatFDColoring` object
8845 
8846   Level: advanced
8847 
8848   Developer Note:
8849   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8850 
8851 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8852 @*/
MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)8853 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8854 {
8855   PetscFunctionBegin;
8856   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8857   PetscFunctionReturn(PETSC_SUCCESS);
8858 }
8859 
8860 /*@
8861   DMGetCompatibility - determine if two `DM`s are compatible
8862 
8863   Collective
8864 
8865   Input Parameters:
8866 + dm1 - the first `DM`
8867 - dm2 - the second `DM`
8868 
8869   Output Parameters:
8870 + compatible - whether or not the two `DM`s are compatible
8871 - set        - whether or not the compatible value was actually determined and set
8872 
8873   Level: advanced
8874 
8875   Notes:
8876   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8877   of the same topology. This implies that the section (field data) on one
8878   "makes sense" with respect to the topology and parallel decomposition of the other.
8879   Loosely speaking, compatible `DM`s represent the same domain and parallel
8880   decomposition, but hold different data.
8881 
8882   Typically, one would confirm compatibility if intending to simultaneously iterate
8883   over a pair of vectors obtained from different `DM`s.
8884 
8885   For example, two `DMDA` objects are compatible if they have the same local
8886   and global sizes and the same stencil width. They can have different numbers
8887   of degrees of freedom per node. Thus, one could use the node numbering from
8888   either `DM` in bounds for a loop over vectors derived from either `DM`.
8889 
8890   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8891   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8892 .vb
8893   ...
8894   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8895   if (set && compatible)  {
8896     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8897     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8898     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8899     for (j=y; j<y+n; ++j) {
8900       for (i=x; i<x+m, ++i) {
8901         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8902       }
8903     }
8904     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8905     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8906   } else {
8907     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8908   }
8909   ...
8910 .ve
8911 
8912   Checking compatibility might be expensive for a given implementation of `DM`,
8913   or might be impossible to unambiguously confirm or deny. For this reason,
8914   this function may decline to determine compatibility, and hence users should
8915   always check the "set" output parameter.
8916 
8917   A `DM` is always compatible with itself.
8918 
8919   In the current implementation, `DM`s which live on "unequal" communicators
8920   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8921   incompatible.
8922 
8923   This function is labeled "Collective," as information about all subdomains
8924   is required on each rank. However, in `DM` implementations which store all this
8925   information locally, this function may be merely "Logically Collective".
8926 
8927   Developer Note:
8928   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8929   iff B is compatible with A. Thus, this function checks the implementations
8930   of both dm and dmc (if they are of different types), attempting to determine
8931   compatibility. It is left to `DM` implementers to ensure that symmetry is
8932   preserved. The simplest way to do this is, when implementing type-specific
8933   logic for this function, is to check for existing logic in the implementation
8934   of other `DM` types and let *set = PETSC_FALSE if found.
8935 
8936 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8937 @*/
DMGetCompatibility(DM dm1,DM dm2,PetscBool * compatible,PetscBool * set)8938 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8939 {
8940   PetscMPIInt compareResult;
8941   DMType      type, type2;
8942   PetscBool   sameType;
8943 
8944   PetscFunctionBegin;
8945   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8946   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8947 
8948   /* Declare a DM compatible with itself */
8949   if (dm1 == dm2) {
8950     *set        = PETSC_TRUE;
8951     *compatible = PETSC_TRUE;
8952     PetscFunctionReturn(PETSC_SUCCESS);
8953   }
8954 
8955   /* Declare a DM incompatible with a DM that lives on an "unequal"
8956      communicator. Note that this does not preclude compatibility with
8957      DMs living on "congruent" or "similar" communicators, but this must be
8958      determined by the implementation-specific logic */
8959   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8960   if (compareResult == MPI_UNEQUAL) {
8961     *set        = PETSC_TRUE;
8962     *compatible = PETSC_FALSE;
8963     PetscFunctionReturn(PETSC_SUCCESS);
8964   }
8965 
8966   /* Pass to the implementation-specific routine, if one exists. */
8967   if (dm1->ops->getcompatibility) {
8968     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8969     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8970   }
8971 
8972   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8973      with an implementation of this function from dm2 */
8974   PetscCall(DMGetType(dm1, &type));
8975   PetscCall(DMGetType(dm2, &type2));
8976   PetscCall(PetscStrcmp(type, type2, &sameType));
8977   if (!sameType && dm2->ops->getcompatibility) {
8978     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8979   } else {
8980     *set = PETSC_FALSE;
8981   }
8982   PetscFunctionReturn(PETSC_SUCCESS);
8983 }
8984 
8985 /*@C
8986   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8987 
8988   Logically Collective
8989 
8990   Input Parameters:
8991 + dm             - the `DM`
8992 . f              - the monitor function
8993 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8994 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8995 
8996   Options Database Key:
8997 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8998                        does not cancel those set via the options database.
8999 
9000   Level: intermediate
9001 
9002   Note:
9003   Several different monitoring routines may be set by calling
9004   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
9005   order in which they were set.
9006 
9007   Fortran Note:
9008   Only a single monitor function can be set for each `DM` object
9009 
9010   Developer Note:
9011   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
9012 
9013 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
9014 @*/
DMMonitorSet(DM dm,PetscErrorCode (* f)(DM,void *),void * mctx,PetscCtxDestroyFn * monitordestroy)9015 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
9016 {
9017   PetscFunctionBegin;
9018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9019   for (PetscInt m = 0; m < dm->numbermonitors; ++m) {
9020     PetscBool identical;
9021 
9022     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)f, mctx, monitordestroy, (PetscErrorCode (*)(void))(PetscVoidFn *)dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
9023     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
9024   }
9025   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9026   dm->monitor[dm->numbermonitors]          = f;
9027   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9028   dm->monitorcontext[dm->numbermonitors++] = mctx;
9029   PetscFunctionReturn(PETSC_SUCCESS);
9030 }
9031 
9032 /*@
9033   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
9034 
9035   Logically Collective
9036 
9037   Input Parameter:
9038 . dm - the DM
9039 
9040   Options Database Key:
9041 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9042   into a code by calls to `DMonitorSet()`, but does not cancel those
9043   set via the options database
9044 
9045   Level: intermediate
9046 
9047   Note:
9048   There is no way to clear one specific monitor from a `DM` object.
9049 
9050 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
9051 @*/
DMMonitorCancel(DM dm)9052 PetscErrorCode DMMonitorCancel(DM dm)
9053 {
9054   PetscInt m;
9055 
9056   PetscFunctionBegin;
9057   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9058   for (m = 0; m < dm->numbermonitors; ++m) {
9059     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
9060   }
9061   dm->numbermonitors = 0;
9062   PetscFunctionReturn(PETSC_SUCCESS);
9063 }
9064 
9065 /*@C
9066   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9067 
9068   Collective
9069 
9070   Input Parameters:
9071 + dm           - `DM` object you wish to monitor
9072 . name         - the monitor type one is seeking
9073 . help         - message indicating what monitoring is done
9074 . manual       - manual page for the monitor
9075 . monitor      - the monitor function, this must use a `PetscViewerFormat` as its context
9076 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `DM` or `PetscViewer` objects
9077 
9078   Output Parameter:
9079 . flg - Flag set if the monitor was created
9080 
9081   Level: developer
9082 
9083 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
9084           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
9085           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
9086           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
9087           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
9088           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
9089           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
9090 @*/
DMMonitorSetFromOptions(DM dm,const char name[],const char help[],const char manual[],PetscErrorCode (* monitor)(DM,void *),PetscErrorCode (* monitorsetup)(DM,PetscViewerAndFormat *),PetscBool * flg)9091 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9092 {
9093   PetscViewer       viewer;
9094   PetscViewerFormat format;
9095 
9096   PetscFunctionBegin;
9097   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9098   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
9099   if (*flg) {
9100     PetscViewerAndFormat *vf;
9101 
9102     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9103     PetscCall(PetscViewerDestroy(&viewer));
9104     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9105     PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
9106   }
9107   PetscFunctionReturn(PETSC_SUCCESS);
9108 }
9109 
9110 /*@
9111   DMMonitor - runs the user provided monitor routines, if they exist
9112 
9113   Collective
9114 
9115   Input Parameter:
9116 . dm - The `DM`
9117 
9118   Level: developer
9119 
9120   Developer Note:
9121   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9122   related to the discretization process seems rather specialized since some `DM` have no
9123   concept of discretization.
9124 
9125 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9126 @*/
DMMonitor(DM dm)9127 PetscErrorCode DMMonitor(DM dm)
9128 {
9129   PetscInt m;
9130 
9131   PetscFunctionBegin;
9132   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9134   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9135   PetscFunctionReturn(PETSC_SUCCESS);
9136 }
9137 
9138 /*@
9139   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9140 
9141   Collective
9142 
9143   Input Parameters:
9144 + dm  - The `DM`
9145 - sol - The solution vector
9146 
9147   Input/Output Parameter:
9148 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9149            contains the error in each field
9150 
9151   Output Parameter:
9152 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9153 
9154   Level: developer
9155 
9156   Note:
9157   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9158 
9159 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9160 @*/
DMComputeError(DM dm,Vec sol,PetscReal errors[],Vec * errorVec)9161 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9162 {
9163   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9164   void    **ctxs;
9165   PetscReal time;
9166   PetscInt  Nf, f, Nds, s;
9167 
9168   PetscFunctionBegin;
9169   PetscCall(DMGetNumFields(dm, &Nf));
9170   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9171   PetscCall(DMGetNumDS(dm, &Nds));
9172   for (s = 0; s < Nds; ++s) {
9173     PetscDS         ds;
9174     DMLabel         label;
9175     IS              fieldIS;
9176     const PetscInt *fields;
9177     PetscInt        dsNf;
9178 
9179     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9180     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9181     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9182     for (f = 0; f < dsNf; ++f) {
9183       const PetscInt field = fields[f];
9184       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9185     }
9186     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9187   }
9188   for (f = 0; f < Nf; ++f) PetscCheck(exactSol[f], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %" PetscInt_FMT, f);
9189   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9190   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9191   if (errorVec) {
9192     DM             edm;
9193     DMPolytopeType ct;
9194     PetscBool      simplex;
9195     PetscInt       dim, cStart, Nf;
9196 
9197     PetscCall(DMClone(dm, &edm));
9198     PetscCall(DMGetDimension(edm, &dim));
9199     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9200     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9201     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9202     PetscCall(DMGetNumFields(dm, &Nf));
9203     for (f = 0; f < Nf; ++f) {
9204       PetscFE         fe, efe;
9205       PetscQuadrature q;
9206       const char     *name;
9207 
9208       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9209       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9210       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9211       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9212       PetscCall(PetscFEGetQuadrature(fe, &q));
9213       PetscCall(PetscFESetQuadrature(efe, q));
9214       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9215       PetscCall(PetscFEDestroy(&efe));
9216     }
9217     PetscCall(DMCreateDS(edm));
9218 
9219     PetscCall(DMCreateGlobalVector(edm, errorVec));
9220     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9221     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9222     PetscCall(DMDestroy(&edm));
9223   }
9224   PetscCall(PetscFree2(exactSol, ctxs));
9225   PetscFunctionReturn(PETSC_SUCCESS);
9226 }
9227 
9228 /*@
9229   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9230 
9231   Not Collective
9232 
9233   Input Parameter:
9234 . dm - The `DM`
9235 
9236   Output Parameter:
9237 . numAux - The number of auxiliary data vectors
9238 
9239   Level: advanced
9240 
9241 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9242 @*/
DMGetNumAuxiliaryVec(DM dm,PetscInt * numAux)9243 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9244 {
9245   PetscFunctionBegin;
9246   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9247   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9248   PetscFunctionReturn(PETSC_SUCCESS);
9249 }
9250 
9251 /*@
9252   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9253 
9254   Not Collective
9255 
9256   Input Parameters:
9257 + dm    - The `DM`
9258 . label - The `DMLabel`
9259 . value - The label value indicating the region
9260 - part  - The equation part, or 0 if unused
9261 
9262   Output Parameter:
9263 . aux - The `Vec` holding auxiliary field data
9264 
9265   Level: advanced
9266 
9267   Note:
9268   If no auxiliary vector is found for this (label, value), (`NULL`, 0, 0) is checked as well.
9269 
9270 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9271 @*/
DMGetAuxiliaryVec(DM dm,DMLabel label,PetscInt value,PetscInt part,Vec * aux)9272 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9273 {
9274   PetscHashAuxKey key, wild = {NULL, 0, 0};
9275   PetscBool       has;
9276 
9277   PetscFunctionBegin;
9278   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9279   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9280   key.label = label;
9281   key.value = value;
9282   key.part  = part;
9283   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9284   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9285   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9286   PetscFunctionReturn(PETSC_SUCCESS);
9287 }
9288 
9289 /*@
9290   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9291 
9292   Not Collective because auxiliary vectors are not parallel
9293 
9294   Input Parameters:
9295 + dm    - The `DM`
9296 . label - The `DMLabel`
9297 . value - The label value indicating the region
9298 . part  - The equation part, or 0 if unused
9299 - aux   - The `Vec` holding auxiliary field data
9300 
9301   Level: advanced
9302 
9303 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9304 @*/
DMSetAuxiliaryVec(DM dm,DMLabel label,PetscInt value,PetscInt part,Vec aux)9305 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9306 {
9307   Vec             old;
9308   PetscHashAuxKey key;
9309 
9310   PetscFunctionBegin;
9311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9312   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9313   key.label = label;
9314   key.value = value;
9315   key.part  = part;
9316   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9317   PetscCall(PetscObjectReference((PetscObject)aux));
9318   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9319   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9320   PetscCall(VecDestroy(&old));
9321   PetscFunctionReturn(PETSC_SUCCESS);
9322 }
9323 
9324 /*@
9325   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9326 
9327   Not Collective
9328 
9329   Input Parameter:
9330 . dm - The `DM`
9331 
9332   Output Parameters:
9333 + labels - The `DMLabel`s for each `Vec`
9334 . values - The label values for each `Vec`
9335 - parts  - The equation parts for each `Vec`
9336 
9337   Level: advanced
9338 
9339   Note:
9340   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9341 
9342 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9343 @*/
DMGetAuxiliaryLabels(DM dm,DMLabel labels[],PetscInt values[],PetscInt parts[])9344 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9345 {
9346   PetscHashAuxKey *keys;
9347   PetscInt         n, i, off = 0;
9348 
9349   PetscFunctionBegin;
9350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9351   PetscAssertPointer(labels, 2);
9352   PetscAssertPointer(values, 3);
9353   PetscAssertPointer(parts, 4);
9354   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9355   PetscCall(PetscMalloc1(n, &keys));
9356   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9357   for (i = 0; i < n; ++i) {
9358     labels[i] = keys[i].label;
9359     values[i] = keys[i].value;
9360     parts[i]  = keys[i].part;
9361   }
9362   PetscCall(PetscFree(keys));
9363   PetscFunctionReturn(PETSC_SUCCESS);
9364 }
9365 
9366 /*@
9367   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9368 
9369   Not Collective
9370 
9371   Input Parameter:
9372 . dm - The `DM`
9373 
9374   Output Parameter:
9375 . dmNew - The new `DM`, now with the same auxiliary data
9376 
9377   Level: advanced
9378 
9379   Note:
9380   This is a shallow copy of the auxiliary vectors
9381 
9382 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9383 @*/
DMCopyAuxiliaryVec(DM dm,DM dmNew)9384 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9385 {
9386   PetscFunctionBegin;
9387   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9388   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9389   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9390   PetscCall(DMClearAuxiliaryVec(dmNew));
9391 
9392   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9393   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9394   {
9395     Vec     *auxData;
9396     PetscInt n, i, off = 0;
9397 
9398     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9399     PetscCall(PetscMalloc1(n, &auxData));
9400     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9401     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9402     PetscCall(PetscFree(auxData));
9403   }
9404   PetscFunctionReturn(PETSC_SUCCESS);
9405 }
9406 
9407 /*@
9408   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9409 
9410   Not Collective
9411 
9412   Input Parameter:
9413 . dm - The `DM`
9414 
9415   Level: advanced
9416 
9417 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9418 @*/
DMClearAuxiliaryVec(DM dm)9419 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9420 {
9421   Vec     *auxData;
9422   PetscInt n, i, off = 0;
9423 
9424   PetscFunctionBegin;
9425   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9426   PetscCall(PetscMalloc1(n, &auxData));
9427   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9428   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9429   PetscCall(PetscFree(auxData));
9430   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9431   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9432   PetscFunctionReturn(PETSC_SUCCESS);
9433 }
9434 
9435 /*@
9436   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9437 
9438   Not Collective
9439 
9440   Input Parameters:
9441 + ct         - The `DMPolytopeType`
9442 . sourceCone - The source arrangement of faces
9443 - targetCone - The target arrangement of faces
9444 
9445   Output Parameters:
9446 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9447 - found - Flag indicating that a suitable orientation was found
9448 
9449   Level: advanced
9450 
9451   Note:
9452   An arrangement is a face order combined with an orientation for each face
9453 
9454   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9455   that labels each arrangement (face ordering plus orientation for each face).
9456 
9457   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9458 
9459 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9460 @*/
DMPolytopeMatchOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt,PetscBool * found)9461 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9462 {
9463   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9464   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9465   PetscInt       o, c;
9466 
9467   PetscFunctionBegin;
9468   if (!nO) {
9469     *ornt  = 0;
9470     *found = PETSC_TRUE;
9471     PetscFunctionReturn(PETSC_SUCCESS);
9472   }
9473   for (o = -nO; o < nO; ++o) {
9474     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9475 
9476     for (c = 0; c < cS; ++c)
9477       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9478     if (c == cS) {
9479       *ornt = o;
9480       break;
9481     }
9482   }
9483   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9484   PetscFunctionReturn(PETSC_SUCCESS);
9485 }
9486 
9487 /*@
9488   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9489 
9490   Not Collective
9491 
9492   Input Parameters:
9493 + ct         - The `DMPolytopeType`
9494 . sourceCone - The source arrangement of faces
9495 - targetCone - The target arrangement of faces
9496 
9497   Output Parameter:
9498 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9499 
9500   Level: advanced
9501 
9502   Note:
9503   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9504 
9505   Developer Note:
9506   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9507 
9508 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9509 @*/
DMPolytopeGetOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt)9510 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9511 {
9512   PetscBool found;
9513 
9514   PetscFunctionBegin;
9515   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9516   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9517   PetscFunctionReturn(PETSC_SUCCESS);
9518 }
9519 
9520 /*@
9521   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9522 
9523   Not Collective
9524 
9525   Input Parameters:
9526 + ct         - The `DMPolytopeType`
9527 . sourceVert - The source arrangement of vertices
9528 - targetVert - The target arrangement of vertices
9529 
9530   Output Parameters:
9531 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9532 - found - Flag indicating that a suitable orientation was found
9533 
9534   Level: advanced
9535 
9536   Notes:
9537   An arrangement is a vertex order
9538 
9539   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9540   that labels each arrangement (vertex ordering).
9541 
9542   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9543 
9544 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9545 @*/
DMPolytopeMatchVertexOrientation(DMPolytopeType ct,const PetscInt sourceVert[],const PetscInt targetVert[],PetscInt * ornt,PetscBool * found)9546 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9547 {
9548   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9549   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9550   PetscInt       o, c;
9551 
9552   PetscFunctionBegin;
9553   if (!nO) {
9554     *ornt  = 0;
9555     *found = PETSC_TRUE;
9556     PetscFunctionReturn(PETSC_SUCCESS);
9557   }
9558   for (o = -nO; o < nO; ++o) {
9559     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9560 
9561     for (c = 0; c < cS; ++c)
9562       if (sourceVert[arr[c]] != targetVert[c]) break;
9563     if (c == cS) {
9564       *ornt = o;
9565       break;
9566     }
9567   }
9568   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9569   PetscFunctionReturn(PETSC_SUCCESS);
9570 }
9571 
9572 /*@
9573   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9574 
9575   Not Collective
9576 
9577   Input Parameters:
9578 + ct         - The `DMPolytopeType`
9579 . sourceCone - The source arrangement of vertices
9580 - targetCone - The target arrangement of vertices
9581 
9582   Output Parameter:
9583 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9584 
9585   Level: advanced
9586 
9587   Note:
9588   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9589 
9590   Developer Note:
9591   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9592 
9593 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9594 @*/
DMPolytopeGetVertexOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt)9595 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9596 {
9597   PetscBool found;
9598 
9599   PetscFunctionBegin;
9600   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9601   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9602   PetscFunctionReturn(PETSC_SUCCESS);
9603 }
9604 
9605 /*@
9606   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9607 
9608   Not Collective
9609 
9610   Input Parameters:
9611 + ct    - The `DMPolytopeType`
9612 - point - Coordinates of the point
9613 
9614   Output Parameter:
9615 . inside - Flag indicating whether the point is inside the reference cell of given type
9616 
9617   Level: advanced
9618 
9619 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9620 @*/
DMPolytopeInCellTest(DMPolytopeType ct,const PetscReal point[],PetscBool * inside)9621 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9622 {
9623   PetscReal sum = 0.0;
9624   PetscInt  d;
9625 
9626   PetscFunctionBegin;
9627   *inside = PETSC_TRUE;
9628   switch (ct) {
9629   case DM_POLYTOPE_TRIANGLE:
9630   case DM_POLYTOPE_TETRAHEDRON:
9631     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9632       if (point[d] < -1.0) {
9633         *inside = PETSC_FALSE;
9634         break;
9635       }
9636       sum += point[d];
9637     }
9638     if (sum > PETSC_SMALL) {
9639       *inside = PETSC_FALSE;
9640       break;
9641     }
9642     break;
9643   case DM_POLYTOPE_QUADRILATERAL:
9644   case DM_POLYTOPE_HEXAHEDRON:
9645     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9646       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9647         *inside = PETSC_FALSE;
9648         break;
9649       }
9650     break;
9651   default:
9652     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9653   }
9654   PetscFunctionReturn(PETSC_SUCCESS);
9655 }
9656 
9657 /*@
9658   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9659 
9660   Logically collective
9661 
9662   Input Parameters:
9663 + dm      - The DM
9664 - reorder - Flag for reordering
9665 
9666   Level: intermediate
9667 
9668 .seealso: `DMReorderSectionGetDefault()`
9669 @*/
DMReorderSectionSetDefault(DM dm,DMReorderDefaultFlag reorder)9670 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9671 {
9672   PetscFunctionBegin;
9673   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9674   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9675   PetscFunctionReturn(PETSC_SUCCESS);
9676 }
9677 
9678 /*@
9679   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9680 
9681   Not collective
9682 
9683   Input Parameter:
9684 . dm - The DM
9685 
9686   Output Parameter:
9687 . reorder - Flag for reordering
9688 
9689   Level: intermediate
9690 
9691 .seealso: `DMReorderSetDefault()`
9692 @*/
DMReorderSectionGetDefault(DM dm,DMReorderDefaultFlag * reorder)9693 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9694 {
9695   PetscFunctionBegin;
9696   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9697   PetscAssertPointer(reorder, 2);
9698   *reorder = DM_REORDER_DEFAULT_NOTSET;
9699   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9700   PetscFunctionReturn(PETSC_SUCCESS);
9701 }
9702 
9703 /*@
9704   DMReorderSectionSetType - Set the type of local section reordering
9705 
9706   Logically collective
9707 
9708   Input Parameters:
9709 + dm      - The DM
9710 - reorder - The reordering method
9711 
9712   Level: intermediate
9713 
9714 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9715 @*/
DMReorderSectionSetType(DM dm,MatOrderingType reorder)9716 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9717 {
9718   PetscFunctionBegin;
9719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9720   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9721   PetscFunctionReturn(PETSC_SUCCESS);
9722 }
9723 
9724 /*@
9725   DMReorderSectionGetType - Get the reordering type for the local section
9726 
9727   Not collective
9728 
9729   Input Parameter:
9730 . dm - The DM
9731 
9732   Output Parameter:
9733 . reorder - The reordering method
9734 
9735   Level: intermediate
9736 
9737 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9738 @*/
DMReorderSectionGetType(DM dm,MatOrderingType * reorder)9739 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9740 {
9741   PetscFunctionBegin;
9742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9743   PetscAssertPointer(reorder, 2);
9744   *reorder = NULL;
9745   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9746   PetscFunctionReturn(PETSC_SUCCESS);
9747 }
9748