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