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