xref: /petsc/src/dm/interface/dm.c (revision a42bd24d6ac9185afbab42a02bd6929e4f15d091)
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 PetscClassId  DM_CLASSID;
10 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction;
11 
12 const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_",0};
13 
14 static PetscErrorCode DMHasCreateInjection_Default(DM dm, PetscBool *flg)
15 {
16   PetscFunctionBegin;
17   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
18   PetscValidPointer(flg,2);
19   *flg = PETSC_FALSE;
20   PetscFunctionReturn(0);
21 }
22 
23 /*@
24   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
25 
26    If you never  call DMSetType()  it will generate an
27    error when you try to use the vector.
28 
29   Collective on MPI_Comm
30 
31   Input Parameter:
32 . comm - The communicator for the DM object
33 
34   Output Parameter:
35 . dm - The DM object
36 
37   Level: beginner
38 
39 .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
40 @*/
41 PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
42 {
43   DM             v;
44   PetscErrorCode ierr;
45 
46   PetscFunctionBegin;
47   PetscValidPointer(dm,2);
48   *dm = NULL;
49   ierr = PetscSysInitializePackage();CHKERRQ(ierr);
50   ierr = VecInitializePackage();CHKERRQ(ierr);
51   ierr = MatInitializePackage();CHKERRQ(ierr);
52   ierr = DMInitializePackage();CHKERRQ(ierr);
53 
54   ierr = PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);CHKERRQ(ierr);
55 
56   v->ltogmap                  = NULL;
57   v->bs                       = 1;
58   v->coloringtype             = IS_COLORING_GLOBAL;
59   ierr                        = PetscSFCreate(comm, &v->sf);CHKERRQ(ierr);
60   ierr                        = PetscSFCreate(comm, &v->defaultSF);CHKERRQ(ierr);
61   v->labels                   = NULL;
62   v->depthLabel               = NULL;
63   v->defaultSection           = NULL;
64   v->defaultGlobalSection     = 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     }
77   }
78   ierr = PetscDSCreate(comm, &v->prob);CHKERRQ(ierr);
79   v->dmBC = NULL;
80   v->coarseMesh = NULL;
81   v->outputSequenceNum = -1;
82   v->outputSequenceVal = 0.0;
83   ierr = DMSetVecType(v,VECSTANDARD);CHKERRQ(ierr);
84   ierr = DMSetMatType(v,MATAIJ);CHKERRQ(ierr);
85   ierr = PetscNew(&(v->labels));CHKERRQ(ierr);
86   v->labels->refct = 1;
87 
88   v->ops->hascreateinjection = DMHasCreateInjection_Default;
89 
90   *dm = v;
91   PetscFunctionReturn(0);
92 }
93 
94 /*@
95   DMClone - Creates a DM object with the same topology as the original.
96 
97   Collective on MPI_Comm
98 
99   Input Parameter:
100 . dm - The original DM object
101 
102   Output Parameter:
103 . newdm  - The new DM object
104 
105   Level: beginner
106 
107 .keywords: DM, topology, create
108 @*/
109 PetscErrorCode DMClone(DM dm, DM *newdm)
110 {
111   PetscSF        sf;
112   Vec            coords;
113   void          *ctx;
114   PetscInt       dim, cdim;
115   PetscErrorCode ierr;
116 
117   PetscFunctionBegin;
118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
119   PetscValidPointer(newdm,2);
120   ierr = DMCreate(PetscObjectComm((PetscObject) dm), newdm);CHKERRQ(ierr);
121   ierr = PetscFree((*newdm)->labels);CHKERRQ(ierr);
122   dm->labels->refct++;
123   (*newdm)->labels = dm->labels;
124   (*newdm)->depthLabel = dm->depthLabel;
125   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
126   ierr = DMSetDimension(*newdm, dim);CHKERRQ(ierr);
127   if (dm->ops->clone) {
128     ierr = (*dm->ops->clone)(dm, newdm);CHKERRQ(ierr);
129   }
130   (*newdm)->setupcalled = dm->setupcalled;
131   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
132   ierr = DMSetPointSF(*newdm, sf);CHKERRQ(ierr);
133   ierr = DMGetApplicationContext(dm, &ctx);CHKERRQ(ierr);
134   ierr = DMSetApplicationContext(*newdm, ctx);CHKERRQ(ierr);
135   if (dm->coordinateDM) {
136     DM           ncdm;
137     PetscSection cs;
138     PetscInt     pEnd = -1, pEndMax = -1;
139 
140     ierr = DMGetDefaultSection(dm->coordinateDM, &cs);CHKERRQ(ierr);
141     if (cs) {ierr = PetscSectionGetChart(cs, NULL, &pEnd);CHKERRQ(ierr);}
142     ierr = MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
143     if (pEndMax >= 0) {
144       ierr = DMClone(dm->coordinateDM, &ncdm);CHKERRQ(ierr);
145       ierr = DMSetDefaultSection(ncdm, cs);CHKERRQ(ierr);
146       ierr = DMSetCoordinateDM(*newdm, ncdm);CHKERRQ(ierr);
147       ierr = DMDestroy(&ncdm);CHKERRQ(ierr);
148     }
149   }
150   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
151   ierr = DMSetCoordinateDim(*newdm, cdim);CHKERRQ(ierr);
152   ierr = DMGetCoordinatesLocal(dm, &coords);CHKERRQ(ierr);
153   if (coords) {
154     ierr = DMSetCoordinatesLocal(*newdm, coords);CHKERRQ(ierr);
155   } else {
156     ierr = DMGetCoordinates(dm, &coords);CHKERRQ(ierr);
157     if (coords) {ierr = DMSetCoordinates(*newdm, coords);CHKERRQ(ierr);}
158   }
159   {
160     PetscBool             isper;
161     const PetscReal      *maxCell, *L;
162     const DMBoundaryType *bd;
163     ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
164     ierr = DMSetPeriodicity(*newdm, isper, maxCell,  L,  bd);CHKERRQ(ierr);
165   }
166   PetscFunctionReturn(0);
167 }
168 
169 /*@C
170        DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
171 
172    Logically Collective on DM
173 
174    Input Parameter:
175 +  da - initial distributed array
176 .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL
177 
178    Options Database:
179 .   -dm_vec_type ctype
180 
181    Level: intermediate
182 
183 .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType()
184 @*/
185 PetscErrorCode  DMSetVecType(DM da,VecType ctype)
186 {
187   PetscErrorCode ierr;
188 
189   PetscFunctionBegin;
190   PetscValidHeaderSpecific(da,DM_CLASSID,1);
191   ierr = PetscFree(da->vectype);CHKERRQ(ierr);
192   ierr = PetscStrallocpy(ctype,(char**)&da->vectype);CHKERRQ(ierr);
193   PetscFunctionReturn(0);
194 }
195 
196 /*@C
197        DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
198 
199    Logically Collective on DM
200 
201    Input Parameter:
202 .  da - initial distributed array
203 
204    Output Parameter:
205 .  ctype - the vector type
206 
207    Level: intermediate
208 
209 .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType
210 @*/
211 PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
212 {
213   PetscFunctionBegin;
214   PetscValidHeaderSpecific(da,DM_CLASSID,1);
215   *ctype = da->vectype;
216   PetscFunctionReturn(0);
217 }
218 
219 /*@
220   VecGetDM - Gets the DM defining the data layout of the vector
221 
222   Not collective
223 
224   Input Parameter:
225 . v - The Vec
226 
227   Output Parameter:
228 . dm - The DM
229 
230   Level: intermediate
231 
232 .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
233 @*/
234 PetscErrorCode VecGetDM(Vec v, DM *dm)
235 {
236   PetscErrorCode ierr;
237 
238   PetscFunctionBegin;
239   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
240   PetscValidPointer(dm,2);
241   ierr = PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
242   PetscFunctionReturn(0);
243 }
244 
245 /*@
246   VecSetDM - Sets the DM defining the data layout of the vector.
247 
248   Not collective
249 
250   Input Parameters:
251 + v - The Vec
252 - dm - The DM
253 
254   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.
255 
256   Level: intermediate
257 
258 .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
259 @*/
260 PetscErrorCode VecSetDM(Vec v, DM dm)
261 {
262   PetscErrorCode ierr;
263 
264   PetscFunctionBegin;
265   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
266   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
267   ierr = PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
268   PetscFunctionReturn(0);
269 }
270 
271 /*@C
272        DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM
273 
274    Logically Collective on DM
275 
276    Input Parameters:
277 +  dm - the DM context
278 -  ctype - the matrix type
279 
280    Options Database:
281 .   -dm_is_coloring_type - global or local
282 
283    Level: intermediate
284 
285 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
286           DMGetISColoringType()
287 @*/
288 PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
289 {
290   PetscFunctionBegin;
291   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
292   dm->coloringtype = ctype;
293   PetscFunctionReturn(0);
294 }
295 
296 /*@C
297        DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM
298 
299    Logically Collective on DM
300 
301    Input Parameter:
302 .  dm - the DM context
303 
304    Output Parameter:
305 .  ctype - the matrix type
306 
307    Options Database:
308 .   -dm_is_coloring_type - global or local
309 
310    Level: intermediate
311 
312 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
313           DMGetISColoringType()
314 @*/
315 PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
316 {
317   PetscFunctionBegin;
318   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
319   *ctype = dm->coloringtype;
320   PetscFunctionReturn(0);
321 }
322 
323 /*@C
324        DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
325 
326    Logically Collective on DM
327 
328    Input Parameters:
329 +  dm - the DM context
330 -  ctype - the matrix type
331 
332    Options Database:
333 .   -dm_mat_type ctype
334 
335    Level: intermediate
336 
337 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
338 @*/
339 PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
340 {
341   PetscErrorCode ierr;
342 
343   PetscFunctionBegin;
344   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
345   ierr = PetscFree(dm->mattype);CHKERRQ(ierr);
346   ierr = PetscStrallocpy(ctype,(char**)&dm->mattype);CHKERRQ(ierr);
347   PetscFunctionReturn(0);
348 }
349 
350 /*@C
351        DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
352 
353    Logically Collective on DM
354 
355    Input Parameter:
356 .  dm - the DM context
357 
358    Output Parameter:
359 .  ctype - the matrix type
360 
361    Options Database:
362 .   -dm_mat_type ctype
363 
364    Level: intermediate
365 
366 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType()
367 @*/
368 PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
369 {
370   PetscFunctionBegin;
371   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
372   *ctype = dm->mattype;
373   PetscFunctionReturn(0);
374 }
375 
376 /*@
377   MatGetDM - Gets the DM defining the data layout of the matrix
378 
379   Not collective
380 
381   Input Parameter:
382 . A - The Mat
383 
384   Output Parameter:
385 . dm - The DM
386 
387   Level: intermediate
388 
389   Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
390                   the Mat through a PetscObjectCompose() operation
391 
392 .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
393 @*/
394 PetscErrorCode MatGetDM(Mat A, DM *dm)
395 {
396   PetscErrorCode ierr;
397 
398   PetscFunctionBegin;
399   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
400   PetscValidPointer(dm,2);
401   ierr = PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
402   PetscFunctionReturn(0);
403 }
404 
405 /*@
406   MatSetDM - Sets the DM defining the data layout of the matrix
407 
408   Not collective
409 
410   Input Parameters:
411 + A - The Mat
412 - dm - The DM
413 
414   Level: intermediate
415 
416   Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
417                   the Mat through a PetscObjectCompose() operation
418 
419 
420 .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
421 @*/
422 PetscErrorCode MatSetDM(Mat A, DM dm)
423 {
424   PetscErrorCode ierr;
425 
426   PetscFunctionBegin;
427   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
428   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
429   ierr = PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
430   PetscFunctionReturn(0);
431 }
432 
433 /*@C
434    DMSetOptionsPrefix - Sets the prefix used for searching for all
435    DM options in the database.
436 
437    Logically Collective on DM
438 
439    Input Parameter:
440 +  da - the DM context
441 -  prefix - the prefix to prepend to all option names
442 
443    Notes:
444    A hyphen (-) must NOT be given at the beginning of the prefix name.
445    The first character of all runtime options is AUTOMATICALLY the hyphen.
446 
447    Level: advanced
448 
449 .keywords: DM, set, options, prefix, database
450 
451 .seealso: DMSetFromOptions()
452 @*/
453 PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
454 {
455   PetscErrorCode ierr;
456 
457   PetscFunctionBegin;
458   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
459   ierr = PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
460   if (dm->sf) {
461     ierr = PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);CHKERRQ(ierr);
462   }
463   if (dm->defaultSF) {
464     ierr = PetscObjectSetOptionsPrefix((PetscObject)dm->defaultSF,prefix);CHKERRQ(ierr);
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 /*@C
470    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
471    DM options in the database.
472 
473    Logically Collective on DM
474 
475    Input Parameters:
476 +  dm - the DM context
477 -  prefix - the prefix string to prepend to all DM option requests
478 
479    Notes:
480    A hyphen (-) must NOT be given at the beginning of the prefix name.
481    The first character of all runtime options is AUTOMATICALLY the hyphen.
482 
483    Level: advanced
484 
485 .keywords: DM, append, options, prefix, database
486 
487 .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
488 @*/
489 PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
490 {
491   PetscErrorCode ierr;
492 
493   PetscFunctionBegin;
494   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
495   ierr = PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
496   PetscFunctionReturn(0);
497 }
498 
499 /*@C
500    DMGetOptionsPrefix - Gets the prefix used for searching for all
501    DM options in the database.
502 
503    Not Collective
504 
505    Input Parameters:
506 .  dm - the DM context
507 
508    Output Parameters:
509 .  prefix - pointer to the prefix string used is returned
510 
511    Notes:
512     On the fortran side, the user should pass in a string 'prefix' of
513    sufficient length to hold the prefix.
514 
515    Level: advanced
516 
517 .keywords: DM, set, options, prefix, database
518 
519 .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
520 @*/
521 PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
522 {
523   PetscErrorCode ierr;
524 
525   PetscFunctionBegin;
526   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
527   ierr = PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
528   PetscFunctionReturn(0);
529 }
530 
531 static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
532 {
533   PetscInt i, refct = ((PetscObject) dm)->refct;
534   DMNamedVecLink nlink;
535   PetscErrorCode ierr;
536 
537   PetscFunctionBegin;
538   *ncrefct = 0;
539   /* count all the circular references of DM and its contained Vecs */
540   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
541     if (dm->localin[i])  refct--;
542     if (dm->globalin[i]) refct--;
543   }
544   for (nlink=dm->namedglobal; nlink; nlink=nlink->next) refct--;
545   for (nlink=dm->namedlocal; nlink; nlink=nlink->next) refct--;
546   if (dm->x) {
547     DM obj;
548     ierr = VecGetDM(dm->x, &obj);CHKERRQ(ierr);
549     if (obj == dm) refct--;
550   }
551   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
552     refct--;
553     if (recurseCoarse) {
554       PetscInt coarseCount;
555 
556       ierr = DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);CHKERRQ(ierr);
557       refct += coarseCount;
558     }
559   }
560   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
561     refct--;
562     if (recurseFine) {
563       PetscInt fineCount;
564 
565       ierr = DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);CHKERRQ(ierr);
566       refct += fineCount;
567     }
568   }
569   *ncrefct = refct;
570   PetscFunctionReturn(0);
571 }
572 
573 PetscErrorCode DMDestroyLabelLinkList(DM dm)
574 {
575   PetscErrorCode ierr;
576 
577   PetscFunctionBegin;
578   if (!--(dm->labels->refct)) {
579     DMLabelLink next = dm->labels->next;
580 
581     /* destroy the labels */
582     while (next) {
583       DMLabelLink tmp = next->next;
584 
585       ierr = DMLabelDestroy(&next->label);CHKERRQ(ierr);
586       ierr = PetscFree(next);CHKERRQ(ierr);
587       next = tmp;
588     }
589     ierr = PetscFree(dm->labels);CHKERRQ(ierr);
590   }
591   PetscFunctionReturn(0);
592 }
593 
594 /*@
595     DMDestroy - Destroys a vector packer or DM.
596 
597     Collective on DM
598 
599     Input Parameter:
600 .   dm - the DM object to destroy
601 
602     Level: developer
603 
604 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
605 
606 @*/
607 PetscErrorCode  DMDestroy(DM *dm)
608 {
609   PetscInt       i, cnt;
610   DMNamedVecLink nlink,nnext;
611   PetscErrorCode ierr;
612 
613   PetscFunctionBegin;
614   if (!*dm) PetscFunctionReturn(0);
615   PetscValidHeaderSpecific((*dm),DM_CLASSID,1);
616 
617   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
618   ierr = DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);CHKERRQ(ierr);
619   --((PetscObject)(*dm))->refct;
620   if (--cnt > 0) {*dm = 0; PetscFunctionReturn(0);}
621   /*
622      Need this test because the dm references the vectors that
623      reference the dm, so destroying the dm calls destroy on the
624      vectors that cause another destroy on the dm
625   */
626   if (((PetscObject)(*dm))->refct < 0) PetscFunctionReturn(0);
627   ((PetscObject) (*dm))->refct = 0;
628   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
629     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
630     ierr = VecDestroy(&(*dm)->localin[i]);CHKERRQ(ierr);
631   }
632   nnext=(*dm)->namedglobal;
633   (*dm)->namedglobal = NULL;
634   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
635     nnext = nlink->next;
636     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
637     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
638     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
639     ierr = PetscFree(nlink);CHKERRQ(ierr);
640   }
641   nnext=(*dm)->namedlocal;
642   (*dm)->namedlocal = NULL;
643   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
644     nnext = nlink->next;
645     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
646     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
647     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
648     ierr = PetscFree(nlink);CHKERRQ(ierr);
649   }
650 
651   /* Destroy the list of hooks */
652   {
653     DMCoarsenHookLink link,next;
654     for (link=(*dm)->coarsenhook; link; link=next) {
655       next = link->next;
656       ierr = PetscFree(link);CHKERRQ(ierr);
657     }
658     (*dm)->coarsenhook = NULL;
659   }
660   {
661     DMRefineHookLink link,next;
662     for (link=(*dm)->refinehook; link; link=next) {
663       next = link->next;
664       ierr = PetscFree(link);CHKERRQ(ierr);
665     }
666     (*dm)->refinehook = NULL;
667   }
668   {
669     DMSubDomainHookLink link,next;
670     for (link=(*dm)->subdomainhook; link; link=next) {
671       next = link->next;
672       ierr = PetscFree(link);CHKERRQ(ierr);
673     }
674     (*dm)->subdomainhook = NULL;
675   }
676   {
677     DMGlobalToLocalHookLink link,next;
678     for (link=(*dm)->gtolhook; link; link=next) {
679       next = link->next;
680       ierr = PetscFree(link);CHKERRQ(ierr);
681     }
682     (*dm)->gtolhook = NULL;
683   }
684   {
685     DMLocalToGlobalHookLink link,next;
686     for (link=(*dm)->ltoghook; link; link=next) {
687       next = link->next;
688       ierr = PetscFree(link);CHKERRQ(ierr);
689     }
690     (*dm)->ltoghook = NULL;
691   }
692   /* Destroy the work arrays */
693   {
694     DMWorkLink link,next;
695     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
696     for (link=(*dm)->workin; link; link=next) {
697       next = link->next;
698       ierr = PetscFree(link->mem);CHKERRQ(ierr);
699       ierr = PetscFree(link);CHKERRQ(ierr);
700     }
701     (*dm)->workin = NULL;
702   }
703   if (!--((*dm)->labels->refct)) {
704     DMLabelLink next = (*dm)->labels->next;
705 
706     /* destroy the labels */
707     while (next) {
708       DMLabelLink tmp = next->next;
709 
710       ierr = DMLabelDestroy(&next->label);CHKERRQ(ierr);
711       ierr = PetscFree(next);CHKERRQ(ierr);
712       next = tmp;
713     }
714     ierr = PetscFree((*dm)->labels);CHKERRQ(ierr);
715   }
716   {
717     DMBoundary next = (*dm)->boundary;
718     while (next) {
719       DMBoundary b = next;
720 
721       next = b->next;
722       ierr = PetscFree(b);CHKERRQ(ierr);
723     }
724   }
725 
726   ierr = PetscObjectDestroy(&(*dm)->dmksp);CHKERRQ(ierr);
727   ierr = PetscObjectDestroy(&(*dm)->dmsnes);CHKERRQ(ierr);
728   ierr = PetscObjectDestroy(&(*dm)->dmts);CHKERRQ(ierr);
729 
730   if ((*dm)->ctx && (*dm)->ctxdestroy) {
731     ierr = (*(*dm)->ctxdestroy)(&(*dm)->ctx);CHKERRQ(ierr);
732   }
733   ierr = VecDestroy(&(*dm)->x);CHKERRQ(ierr);
734   ierr = MatFDColoringDestroy(&(*dm)->fd);CHKERRQ(ierr);
735   ierr = DMClearGlobalVectors(*dm);CHKERRQ(ierr);
736   ierr = ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);CHKERRQ(ierr);
737   ierr = PetscFree((*dm)->vectype);CHKERRQ(ierr);
738   ierr = PetscFree((*dm)->mattype);CHKERRQ(ierr);
739 
740   ierr = PetscSectionDestroy(&(*dm)->defaultSection);CHKERRQ(ierr);
741   ierr = PetscSectionDestroy(&(*dm)->defaultGlobalSection);CHKERRQ(ierr);
742   ierr = PetscLayoutDestroy(&(*dm)->map);CHKERRQ(ierr);
743   ierr = PetscSectionDestroy(&(*dm)->defaultConstraintSection);CHKERRQ(ierr);
744   ierr = MatDestroy(&(*dm)->defaultConstraintMat);CHKERRQ(ierr);
745   ierr = PetscSFDestroy(&(*dm)->sf);CHKERRQ(ierr);
746   ierr = PetscSFDestroy(&(*dm)->defaultSF);CHKERRQ(ierr);
747   if ((*dm)->useNatural) {
748     if ((*dm)->sfNatural) {
749       ierr = PetscSFDestroy(&(*dm)->sfNatural);CHKERRQ(ierr);
750     }
751     ierr = PetscObjectDereference((PetscObject) (*dm)->sfMigration);CHKERRQ(ierr);
752   }
753   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
754     ierr = DMSetFineDM((*dm)->coarseMesh,NULL);CHKERRQ(ierr);
755   }
756   ierr = DMDestroy(&(*dm)->coarseMesh);CHKERRQ(ierr);
757   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
758     ierr = DMSetCoarseDM((*dm)->fineMesh,NULL);CHKERRQ(ierr);
759   }
760   ierr = DMDestroy(&(*dm)->fineMesh);CHKERRQ(ierr);
761   ierr = DMFieldDestroy(&(*dm)->coordinateField);CHKERRQ(ierr);
762   ierr = DMDestroy(&(*dm)->coordinateDM);CHKERRQ(ierr);
763   ierr = VecDestroy(&(*dm)->coordinates);CHKERRQ(ierr);
764   ierr = VecDestroy(&(*dm)->coordinatesLocal);CHKERRQ(ierr);
765   ierr = PetscFree3((*dm)->L,(*dm)->maxCell,(*dm)->bdtype);CHKERRQ(ierr);
766 
767   ierr = PetscDSDestroy(&(*dm)->prob);CHKERRQ(ierr);
768   ierr = DMDestroy(&(*dm)->dmBC);CHKERRQ(ierr);
769   /* if memory was published with SAWs then destroy it */
770   ierr = PetscObjectSAWsViewOff((PetscObject)*dm);CHKERRQ(ierr);
771 
772   ierr = (*(*dm)->ops->destroy)(*dm);CHKERRQ(ierr);
773   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
774   ierr = PetscHeaderDestroy(dm);CHKERRQ(ierr);
775   PetscFunctionReturn(0);
776 }
777 
778 /*@
779     DMSetUp - sets up the data structures inside a DM object
780 
781     Collective on DM
782 
783     Input Parameter:
784 .   dm - the DM object to setup
785 
786     Level: developer
787 
788 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
789 
790 @*/
791 PetscErrorCode  DMSetUp(DM dm)
792 {
793   PetscErrorCode ierr;
794 
795   PetscFunctionBegin;
796   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
797   if (dm->setupcalled) PetscFunctionReturn(0);
798   if (dm->ops->setup) {
799     ierr = (*dm->ops->setup)(dm);CHKERRQ(ierr);
800   }
801   dm->setupcalled = PETSC_TRUE;
802   PetscFunctionReturn(0);
803 }
804 
805 /*@
806     DMSetFromOptions - sets parameters in a DM from the options database
807 
808     Collective on DM
809 
810     Input Parameter:
811 .   dm - the DM object to set options for
812 
813     Options Database:
814 +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
815 .   -dm_vec_type <type>  - type of vector to create inside DM
816 .   -dm_mat_type <type>  - type of matrix to create inside DM
817 -   -dm_is_coloring_type - <global or local>
818 
819     Level: developer
820 
821 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
822 
823 @*/
824 PetscErrorCode  DMSetFromOptions(DM dm)
825 {
826   char           typeName[256];
827   PetscBool      flg;
828   PetscErrorCode ierr;
829 
830   PetscFunctionBegin;
831   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
832   if (dm->prob) {
833     ierr = PetscDSSetFromOptions(dm->prob);CHKERRQ(ierr);
834   }
835   if (dm->sf) {
836     ierr = PetscSFSetFromOptions(dm->sf);CHKERRQ(ierr);
837   }
838   if (dm->defaultSF) {
839     ierr = PetscSFSetFromOptions(dm->defaultSF);CHKERRQ(ierr);
840   }
841   ierr = PetscObjectOptionsBegin((PetscObject)dm);CHKERRQ(ierr);
842   ierr = PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);CHKERRQ(ierr);
843   ierr = PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);CHKERRQ(ierr);
844   if (flg) {
845     ierr = DMSetVecType(dm,typeName);CHKERRQ(ierr);
846   }
847   ierr = PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);CHKERRQ(ierr);
848   if (flg) {
849     ierr = DMSetMatType(dm,typeName);CHKERRQ(ierr);
850   }
851   ierr = PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);CHKERRQ(ierr);
852   if (dm->ops->setfromoptions) {
853     ierr = (*dm->ops->setfromoptions)(PetscOptionsObject,dm);CHKERRQ(ierr);
854   }
855   /* process any options handlers added with PetscObjectAddOptionsHandler() */
856   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);CHKERRQ(ierr);
857   ierr = PetscOptionsEnd();CHKERRQ(ierr);
858   PetscFunctionReturn(0);
859 }
860 
861 /*@C
862     DMView - Views a DM
863 
864     Collective on DM
865 
866     Input Parameter:
867 +   dm - the DM object to view
868 -   v - the viewer
869 
870     Level: beginner
871 
872 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
873 
874 @*/
875 PetscErrorCode  DMView(DM dm,PetscViewer v)
876 {
877   PetscErrorCode    ierr;
878   PetscBool         isbinary;
879   PetscMPIInt       size;
880   PetscViewerFormat format;
881 
882   PetscFunctionBegin;
883   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
884   if (!v) {
885     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);CHKERRQ(ierr);
886   }
887   ierr = PetscViewerGetFormat(v,&format);CHKERRQ(ierr);
888   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);CHKERRQ(ierr);
889   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(0);
890   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);CHKERRQ(ierr);
891   ierr = PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
892   if (isbinary) {
893     PetscInt classid = DM_FILE_CLASSID;
894     char     type[256];
895 
896     ierr = PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
897     ierr = PetscStrncpy(type,((PetscObject)dm)->type_name,256);CHKERRQ(ierr);
898     ierr = PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
899   }
900   if (dm->ops->view) {
901     ierr = (*dm->ops->view)(dm,v);CHKERRQ(ierr);
902   }
903   PetscFunctionReturn(0);
904 }
905 
906 /*@
907     DMCreateGlobalVector - Creates a global vector from a DM object
908 
909     Collective on DM
910 
911     Input Parameter:
912 .   dm - the DM object
913 
914     Output Parameter:
915 .   vec - the global vector
916 
917     Level: beginner
918 
919 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
920 
921 @*/
922 PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
923 {
924   PetscErrorCode ierr;
925 
926   PetscFunctionBegin;
927   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
928   ierr = (*dm->ops->createglobalvector)(dm,vec);CHKERRQ(ierr);
929   PetscFunctionReturn(0);
930 }
931 
932 /*@
933     DMCreateLocalVector - Creates a local vector from a DM object
934 
935     Not Collective
936 
937     Input Parameter:
938 .   dm - the DM object
939 
940     Output Parameter:
941 .   vec - the local vector
942 
943     Level: beginner
944 
945 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
946 
947 @*/
948 PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
949 {
950   PetscErrorCode ierr;
951 
952   PetscFunctionBegin;
953   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
954   ierr = (*dm->ops->createlocalvector)(dm,vec);CHKERRQ(ierr);
955   PetscFunctionReturn(0);
956 }
957 
958 /*@
959    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
960 
961    Collective on DM
962 
963    Input Parameter:
964 .  dm - the DM that provides the mapping
965 
966    Output Parameter:
967 .  ltog - the mapping
968 
969    Level: intermediate
970 
971    Notes:
972    This mapping can then be used by VecSetLocalToGlobalMapping() or
973    MatSetLocalToGlobalMapping().
974 
975 .seealso: DMCreateLocalVector()
976 @*/
977 PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
978 {
979   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];
980   PetscErrorCode ierr;
981 
982   PetscFunctionBegin;
983   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
984   PetscValidPointer(ltog,2);
985   if (!dm->ltogmap) {
986     PetscSection section, sectionGlobal;
987 
988     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
989     if (section) {
990       const PetscInt *cdofs;
991       PetscInt       *ltog;
992       PetscInt        pStart, pEnd, n, p, k, l;
993 
994       ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
995       ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
996       ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
997       ierr = PetscMalloc1(n, &ltog);CHKERRQ(ierr); /* We want the local+overlap size */
998       for (p = pStart, l = 0; p < pEnd; ++p) {
999         PetscInt bdof, cdof, dof, off, c, cind = 0;
1000 
1001         /* Should probably use constrained dofs */
1002         ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
1003         ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
1004         ierr = PetscSectionGetConstraintIndices(section, p, &cdofs);CHKERRQ(ierr);
1005         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
1006         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1007         bdof = cdof && (dof-cdof) ? 1 : dof;
1008         if (dof) {
1009           if (bs < 0)          {bs = bdof;}
1010           else if (bs != bdof) {bs = 1;}
1011         }
1012         for (c = 0; c < dof; ++c, ++l) {
1013           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1014           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
1015         }
1016       }
1017       /* Must have same blocksize on all procs (some might have no points) */
1018       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1019       ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
1020       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1021       else                            {bs = bsMinMax[0];}
1022       bs = bs < 0 ? 1 : bs;
1023       /* Must reduce indices by blocksize */
1024       if (bs > 1) {
1025         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1026         n /= bs;
1027       }
1028       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);CHKERRQ(ierr);
1029       ierr = PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);CHKERRQ(ierr);
1030     } else {
1031       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
1032       ierr = (*dm->ops->getlocaltoglobalmapping)(dm);CHKERRQ(ierr);
1033     }
1034   }
1035   *ltog = dm->ltogmap;
1036   PetscFunctionReturn(0);
1037 }
1038 
1039 /*@
1040    DMGetBlockSize - Gets the inherent block size associated with a DM
1041 
1042    Not Collective
1043 
1044    Input Parameter:
1045 .  dm - the DM with block structure
1046 
1047    Output Parameter:
1048 .  bs - the block size, 1 implies no exploitable block structure
1049 
1050    Level: intermediate
1051 
1052 .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1053 @*/
1054 PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1055 {
1056   PetscFunctionBegin;
1057   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1058   PetscValidPointer(bs,2);
1059   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1060   *bs = dm->bs;
1061   PetscFunctionReturn(0);
1062 }
1063 
1064 /*@
1065     DMCreateInterpolation - Gets interpolation matrix between two DM objects
1066 
1067     Collective on DM
1068 
1069     Input Parameter:
1070 +   dm1 - the DM object
1071 -   dm2 - the second, finer DM object
1072 
1073     Output Parameter:
1074 +  mat - the interpolation
1075 -  vec - the scaling (optional)
1076 
1077     Level: developer
1078 
1079     Notes:
1080     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1081         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1082 
1083         For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1084         EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1085 
1086 
1087 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction()
1088 
1089 @*/
1090 PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
1091 {
1092   PetscErrorCode ierr;
1093 
1094   PetscFunctionBegin;
1095   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
1096   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
1097   ierr = PetscLogEventBegin(DM_CreateInterpolation,dm1,dm2,0,0);CHKERRQ(ierr);
1098   ierr = (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);CHKERRQ(ierr);
1099   ierr = PetscLogEventEnd(DM_CreateInterpolation,dm1,dm2,0,0);CHKERRQ(ierr);
1100   PetscFunctionReturn(0);
1101 }
1102 
1103 /*@
1104     DMCreateRestriction - Gets restriction matrix between two DM objects
1105 
1106     Collective on DM
1107 
1108     Input Parameter:
1109 +   dm1 - the DM object
1110 -   dm2 - the second, finer DM object
1111 
1112     Output Parameter:
1113 .  mat - the restriction
1114 
1115 
1116     Level: developer
1117 
1118     Notes:
1119     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1120         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1121 
1122 
1123 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()
1124 
1125 @*/
1126 PetscErrorCode  DMCreateRestriction(DM dm1,DM dm2,Mat *mat)
1127 {
1128   PetscErrorCode ierr;
1129 
1130   PetscFunctionBegin;
1131   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
1132   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
1133   ierr = PetscLogEventBegin(DM_CreateRestriction,dm1,dm2,0,0);CHKERRQ(ierr);
1134   if (!dm1->ops->createrestriction) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateRestriction not implemented for this type");
1135   ierr = (*dm1->ops->createrestriction)(dm1,dm2,mat);CHKERRQ(ierr);
1136   ierr = PetscLogEventEnd(DM_CreateRestriction,dm1,dm2,0,0);CHKERRQ(ierr);
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 /*@
1141     DMCreateInjection - Gets injection matrix between two DM objects
1142 
1143     Collective on DM
1144 
1145     Input Parameter:
1146 +   dm1 - the DM object
1147 -   dm2 - the second, finer DM object
1148 
1149     Output Parameter:
1150 .   mat - the injection
1151 
1152     Level: developer
1153 
1154    Notes:
1155     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1156         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
1157 
1158 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
1159 
1160 @*/
1161 PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,Mat *mat)
1162 {
1163   PetscErrorCode ierr;
1164 
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
1167   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
1168   if (!dm1->ops->getinjection) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateInjection not implemented for this type");
1169   ierr = (*dm1->ops->getinjection)(dm1,dm2,mat);CHKERRQ(ierr);
1170   PetscFunctionReturn(0);
1171 }
1172 
1173 /*@
1174   DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j
1175 
1176   Collective on DM
1177 
1178   Input Parameter:
1179 + dm1 - the DM object
1180 - dm2 - the second, finer DM object
1181 
1182   Output Parameter:
1183 . mat - the interpolation
1184 
1185   Level: developer
1186 
1187 .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1188 @*/
1189 PetscErrorCode DMCreateMassMatrix(DM dm1, DM dm2, Mat *mat)
1190 {
1191   PetscErrorCode ierr;
1192 
1193   PetscFunctionBegin;
1194   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
1195   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
1196   ierr = (*dm1->ops->createmassmatrix)(dm1, dm2, mat);CHKERRQ(ierr);
1197   PetscFunctionReturn(0);
1198 }
1199 
1200 /*@
1201     DMCreateColoring - Gets coloring for a DM
1202 
1203     Collective on DM
1204 
1205     Input Parameter:
1206 +   dm - the DM object
1207 -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL
1208 
1209     Output Parameter:
1210 .   coloring - the coloring
1211 
1212     Level: developer
1213 
1214 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType()
1215 
1216 @*/
1217 PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1218 {
1219   PetscErrorCode ierr;
1220 
1221   PetscFunctionBegin;
1222   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1223   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
1224   ierr = (*dm->ops->getcoloring)(dm,ctype,coloring);CHKERRQ(ierr);
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 /*@
1229     DMCreateMatrix - Gets empty Jacobian for a DM
1230 
1231     Collective on DM
1232 
1233     Input Parameter:
1234 .   dm - the DM object
1235 
1236     Output Parameter:
1237 .   mat - the empty Jacobian
1238 
1239     Level: beginner
1240 
1241     Notes:
1242     This properly preallocates the number of nonzeros in the sparse matrix so you
1243        do not need to do it yourself.
1244 
1245        By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1246        the nonzero pattern call DMSetMatrixPreallocateOnly()
1247 
1248        For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1249        internally by PETSc.
1250 
1251        For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1252        the indices for the global numbering for DMDAs which is complicated.
1253 
1254 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1255 
1256 @*/
1257 PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1258 {
1259   PetscErrorCode ierr;
1260 
1261   PetscFunctionBegin;
1262   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1263   ierr = MatInitializePackage();CHKERRQ(ierr);
1264   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1265   PetscValidPointer(mat,3);
1266   ierr = (*dm->ops->creatematrix)(dm,mat);CHKERRQ(ierr);
1267   PetscFunctionReturn(0);
1268 }
1269 
1270 /*@
1271   DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1272     preallocated but the nonzero structure and zero values will not be set.
1273 
1274   Logically Collective on DM
1275 
1276   Input Parameter:
1277 + dm - the DM
1278 - only - PETSC_TRUE if only want preallocation
1279 
1280   Level: developer
1281 .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1282 @*/
1283 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1284 {
1285   PetscFunctionBegin;
1286   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1287   dm->prealloc_only = only;
1288   PetscFunctionReturn(0);
1289 }
1290 
1291 /*@
1292   DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1293     but the array for values will not be allocated.
1294 
1295   Logically Collective on DM
1296 
1297   Input Parameter:
1298 + dm - the DM
1299 - only - PETSC_TRUE if only want matrix stucture
1300 
1301   Level: developer
1302 .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1303 @*/
1304 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1305 {
1306   PetscFunctionBegin;
1307   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1308   dm->structure_only = only;
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 /*@C
1313   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1314 
1315   Not Collective
1316 
1317   Input Parameters:
1318 + dm - the DM object
1319 . count - The minium size
1320 - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1321 
1322   Output Parameter:
1323 . array - the work array
1324 
1325   Level: developer
1326 
1327 .seealso DMDestroy(), DMCreate()
1328 @*/
1329 PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1330 {
1331   PetscErrorCode ierr;
1332   DMWorkLink     link;
1333   PetscMPIInt    dsize;
1334 
1335   PetscFunctionBegin;
1336   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1337   PetscValidPointer(mem,4);
1338   if (dm->workin) {
1339     link       = dm->workin;
1340     dm->workin = dm->workin->next;
1341   } else {
1342     ierr = PetscNewLog(dm,&link);CHKERRQ(ierr);
1343   }
1344   ierr = MPI_Type_size(dtype,&dsize);CHKERRQ(ierr);
1345   if (((size_t)dsize*count) > link->bytes) {
1346     ierr        = PetscFree(link->mem);CHKERRQ(ierr);
1347     ierr        = PetscMalloc(dsize*count,&link->mem);CHKERRQ(ierr);
1348     link->bytes = dsize*count;
1349   }
1350   link->next   = dm->workout;
1351   dm->workout  = link;
1352   *(void**)mem = link->mem;
1353   PetscFunctionReturn(0);
1354 }
1355 
1356 /*@C
1357   DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1358 
1359   Not Collective
1360 
1361   Input Parameters:
1362 + dm - the DM object
1363 . count - The minium size
1364 - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1365 
1366   Output Parameter:
1367 . array - the work array
1368 
1369   Level: developer
1370 
1371   Developer Notes:
1372     count and dtype are ignored, they are only needed for DMGetWorkArray()
1373 .seealso DMDestroy(), DMCreate()
1374 @*/
1375 PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1376 {
1377   DMWorkLink *p,link;
1378 
1379   PetscFunctionBegin;
1380   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1381   PetscValidPointer(mem,4);
1382   for (p=&dm->workout; (link=*p); p=&link->next) {
1383     if (link->mem == *(void**)mem) {
1384       *p           = link->next;
1385       link->next   = dm->workin;
1386       dm->workin   = link;
1387       *(void**)mem = NULL;
1388       PetscFunctionReturn(0);
1389     }
1390   }
1391   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1392 }
1393 
1394 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1395 {
1396   PetscFunctionBegin;
1397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1398   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1399   dm->nullspaceConstructors[field] = nullsp;
1400   PetscFunctionReturn(0);
1401 }
1402 
1403 /*@C
1404   DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1405 
1406   Not collective
1407 
1408   Input Parameter:
1409 . dm - the DM object
1410 
1411   Output Parameters:
1412 + numFields  - The number of fields (or NULL if not requested)
1413 . fieldNames - The name for each field (or NULL if not requested)
1414 - fields     - The global indices for each field (or NULL if not requested)
1415 
1416   Level: intermediate
1417 
1418   Notes:
1419   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1420   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1421   PetscFree().
1422 
1423 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1424 @*/
1425 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1426 {
1427   PetscSection   section, sectionGlobal;
1428   PetscErrorCode ierr;
1429 
1430   PetscFunctionBegin;
1431   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1432   if (numFields) {
1433     PetscValidPointer(numFields,2);
1434     *numFields = 0;
1435   }
1436   if (fieldNames) {
1437     PetscValidPointer(fieldNames,3);
1438     *fieldNames = NULL;
1439   }
1440   if (fields) {
1441     PetscValidPointer(fields,4);
1442     *fields = NULL;
1443   }
1444   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1445   if (section) {
1446     PetscInt *fieldSizes, **fieldIndices;
1447     PetscInt nF, f, pStart, pEnd, p;
1448 
1449     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1450     ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1451     ierr = PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);CHKERRQ(ierr);
1452     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1453     for (f = 0; f < nF; ++f) {
1454       fieldSizes[f] = 0;
1455     }
1456     for (p = pStart; p < pEnd; ++p) {
1457       PetscInt gdof;
1458 
1459       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1460       if (gdof > 0) {
1461         for (f = 0; f < nF; ++f) {
1462           PetscInt fdof, fcdof;
1463 
1464           ierr           = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1465           ierr           = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1466           fieldSizes[f] += fdof-fcdof;
1467         }
1468       }
1469     }
1470     for (f = 0; f < nF; ++f) {
1471       ierr          = PetscMalloc1(fieldSizes[f], &fieldIndices[f]);CHKERRQ(ierr);
1472       fieldSizes[f] = 0;
1473     }
1474     for (p = pStart; p < pEnd; ++p) {
1475       PetscInt gdof, goff;
1476 
1477       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1478       if (gdof > 0) {
1479         ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1480         for (f = 0; f < nF; ++f) {
1481           PetscInt fdof, fcdof, fc;
1482 
1483           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1484           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1485           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1486             fieldIndices[f][fieldSizes[f]] = goff++;
1487           }
1488         }
1489       }
1490     }
1491     if (numFields) *numFields = nF;
1492     if (fieldNames) {
1493       ierr = PetscMalloc1(nF, fieldNames);CHKERRQ(ierr);
1494       for (f = 0; f < nF; ++f) {
1495         const char *fieldName;
1496 
1497         ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1498         ierr = PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);CHKERRQ(ierr);
1499       }
1500     }
1501     if (fields) {
1502       ierr = PetscMalloc1(nF, fields);CHKERRQ(ierr);
1503       for (f = 0; f < nF; ++f) {
1504         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);CHKERRQ(ierr);
1505       }
1506     }
1507     ierr = PetscFree2(fieldSizes,fieldIndices);CHKERRQ(ierr);
1508   } else if (dm->ops->createfieldis) {
1509     ierr = (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);CHKERRQ(ierr);
1510   }
1511   PetscFunctionReturn(0);
1512 }
1513 
1514 
1515 /*@C
1516   DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1517                           corresponding to different fields: each IS contains the global indices of the dofs of the
1518                           corresponding field. The optional list of DMs define the DM for each subproblem.
1519                           Generalizes DMCreateFieldIS().
1520 
1521   Not collective
1522 
1523   Input Parameter:
1524 . dm - the DM object
1525 
1526   Output Parameters:
1527 + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1528 . namelist  - The name for each field (or NULL if not requested)
1529 . islist    - The global indices for each field (or NULL if not requested)
1530 - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1531 
1532   Level: intermediate
1533 
1534   Notes:
1535   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1536   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1537   and all of the arrays should be freed with PetscFree().
1538 
1539 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1540 @*/
1541 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1542 {
1543   PetscErrorCode ierr;
1544 
1545   PetscFunctionBegin;
1546   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1547   if (len) {
1548     PetscValidPointer(len,2);
1549     *len = 0;
1550   }
1551   if (namelist) {
1552     PetscValidPointer(namelist,3);
1553     *namelist = 0;
1554   }
1555   if (islist) {
1556     PetscValidPointer(islist,4);
1557     *islist = 0;
1558   }
1559   if (dmlist) {
1560     PetscValidPointer(dmlist,5);
1561     *dmlist = 0;
1562   }
1563   /*
1564    Is it a good idea to apply the following check across all impls?
1565    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1566    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1567    */
1568   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1569   if (!dm->ops->createfielddecomposition) {
1570     PetscSection section;
1571     PetscInt     numFields, f;
1572 
1573     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1574     if (section) {ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);}
1575     if (section && numFields && dm->ops->createsubdm) {
1576       if (len) *len = numFields;
1577       if (namelist) {ierr = PetscMalloc1(numFields,namelist);CHKERRQ(ierr);}
1578       if (islist)   {ierr = PetscMalloc1(numFields,islist);CHKERRQ(ierr);}
1579       if (dmlist)   {ierr = PetscMalloc1(numFields,dmlist);CHKERRQ(ierr);}
1580       for (f = 0; f < numFields; ++f) {
1581         const char *fieldName;
1582 
1583         ierr = DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);CHKERRQ(ierr);
1584         if (namelist) {
1585           ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1586           ierr = PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);CHKERRQ(ierr);
1587         }
1588       }
1589     } else {
1590       ierr = DMCreateFieldIS(dm, len, namelist, islist);CHKERRQ(ierr);
1591       /* By default there are no DMs associated with subproblems. */
1592       if (dmlist) *dmlist = NULL;
1593     }
1594   } else {
1595     ierr = (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);CHKERRQ(ierr);
1596   }
1597   PetscFunctionReturn(0);
1598 }
1599 
1600 /*@
1601   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1602                   The fields are defined by DMCreateFieldIS().
1603 
1604   Not collective
1605 
1606   Input Parameters:
1607 + dm        - The DM object
1608 . numFields - The number of fields in this subproblem
1609 - fields    - The field numbers of the selected fields
1610 
1611   Output Parameters:
1612 + is - The global indices for the subproblem
1613 - subdm - The DM for the subproblem
1614 
1615   Level: intermediate
1616 
1617 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1618 @*/
1619 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1620 {
1621   PetscErrorCode ierr;
1622 
1623   PetscFunctionBegin;
1624   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1625   PetscValidPointer(fields,3);
1626   if (is) PetscValidPointer(is,4);
1627   if (subdm) PetscValidPointer(subdm,5);
1628   if (dm->ops->createsubdm) {
1629     ierr = (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1630   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1631   PetscFunctionReturn(0);
1632 }
1633 
1634 /*@C
1635   DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.
1636 
1637   Not collective
1638 
1639   Input Parameter:
1640 + dms - The DM objects
1641 - len - The number of DMs
1642 
1643   Output Parameters:
1644 + is - The global indices for the subproblem, or NULL
1645 - superdm - The DM for the superproblem
1646 
1647   Level: intermediate
1648 
1649 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1650 @*/
1651 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1652 {
1653   PetscInt       i;
1654   PetscErrorCode ierr;
1655 
1656   PetscFunctionBegin;
1657   PetscValidPointer(dms,1);
1658   for (i = 0; i < len; ++i) {PetscValidHeaderSpecific(dms[i],DM_CLASSID,1);}
1659   if (is) PetscValidPointer(is,3);
1660   PetscValidPointer(superdm,4);
1661   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1662   if (len) {
1663     if (dms[0]->ops->createsuperdm) {ierr = (*dms[0]->ops->createsuperdm)(dms, len, is, superdm);CHKERRQ(ierr);}
1664     else SETERRQ(PetscObjectComm((PetscObject) dms[0]), PETSC_ERR_SUP, "This type has no DMCreateSuperDM implementation defined");
1665   }
1666   PetscFunctionReturn(0);
1667 }
1668 
1669 
1670 /*@C
1671   DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1672                           corresponding to restrictions to pairs nested subdomains: each IS contains the global
1673                           indices of the dofs of the corresponding subdomains.  The inner subdomains conceptually
1674                           define a nonoverlapping covering, while outer subdomains can overlap.
1675                           The optional list of DMs define the DM for each subproblem.
1676 
1677   Not collective
1678 
1679   Input Parameter:
1680 . dm - the DM object
1681 
1682   Output Parameters:
1683 + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1684 . namelist    - The name for each subdomain (or NULL if not requested)
1685 . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1686 . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1687 - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1688 
1689   Level: intermediate
1690 
1691   Notes:
1692   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1693   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1694   and all of the arrays should be freed with PetscFree().
1695 
1696 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1697 @*/
1698 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1699 {
1700   PetscErrorCode      ierr;
1701   DMSubDomainHookLink link;
1702   PetscInt            i,l;
1703 
1704   PetscFunctionBegin;
1705   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1706   if (len)           {PetscValidPointer(len,2);            *len         = 0;}
1707   if (namelist)      {PetscValidPointer(namelist,3);       *namelist    = NULL;}
1708   if (innerislist)   {PetscValidPointer(innerislist,4);    *innerislist = NULL;}
1709   if (outerislist)   {PetscValidPointer(outerislist,5);    *outerislist = NULL;}
1710   if (dmlist)        {PetscValidPointer(dmlist,6);         *dmlist      = NULL;}
1711   /*
1712    Is it a good idea to apply the following check across all impls?
1713    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1714    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1715    */
1716   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1717   if (dm->ops->createdomaindecomposition) {
1718     ierr = (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);CHKERRQ(ierr);
1719     /* copy subdomain hooks and context over to the subdomain DMs */
1720     if (dmlist && *dmlist) {
1721       for (i = 0; i < l; i++) {
1722         for (link=dm->subdomainhook; link; link=link->next) {
1723           if (link->ddhook) {ierr = (*link->ddhook)(dm,(*dmlist)[i],link->ctx);CHKERRQ(ierr);}
1724         }
1725         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1726       }
1727     }
1728     if (len) *len = l;
1729   }
1730   PetscFunctionReturn(0);
1731 }
1732 
1733 
1734 /*@C
1735   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
1736 
1737   Not collective
1738 
1739   Input Parameters:
1740 + dm - the DM object
1741 . n  - the number of subdomain scatters
1742 - subdms - the local subdomains
1743 
1744   Output Parameters:
1745 + n     - the number of scatters returned
1746 . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1747 . oscat - scatter from global vector to overlapping global vector entries on subdomain
1748 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
1749 
1750   Notes:
1751     This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
1752   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
1753   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
1754   solution and residual data.
1755 
1756   Level: developer
1757 
1758 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1759 @*/
1760 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1761 {
1762   PetscErrorCode ierr;
1763 
1764   PetscFunctionBegin;
1765   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1766   PetscValidPointer(subdms,3);
1767   if (dm->ops->createddscatters) {
1768     ierr = (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);CHKERRQ(ierr);
1769   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionScatter implementation defined");
1770   PetscFunctionReturn(0);
1771 }
1772 
1773 /*@
1774   DMRefine - Refines a DM object
1775 
1776   Collective on DM
1777 
1778   Input Parameter:
1779 + dm   - the DM object
1780 - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1781 
1782   Output Parameter:
1783 . dmf - the refined DM, or NULL
1784 
1785   Note: If no refinement was done, the return value is NULL
1786 
1787   Level: developer
1788 
1789 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1790 @*/
1791 PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1792 {
1793   PetscErrorCode   ierr;
1794   DMRefineHookLink link;
1795 
1796   PetscFunctionBegin;
1797   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1798   ierr = PetscLogEventBegin(DM_Refine,dm,0,0,0);CHKERRQ(ierr);
1799   if (!dm->ops->refine) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot refine");
1800   ierr = (*dm->ops->refine)(dm,comm,dmf);CHKERRQ(ierr);
1801   if (*dmf) {
1802     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
1803 
1804     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);CHKERRQ(ierr);
1805 
1806     (*dmf)->ctx       = dm->ctx;
1807     (*dmf)->leveldown = dm->leveldown;
1808     (*dmf)->levelup   = dm->levelup + 1;
1809 
1810     ierr = DMSetMatType(*dmf,dm->mattype);CHKERRQ(ierr);
1811     for (link=dm->refinehook; link; link=link->next) {
1812       if (link->refinehook) {
1813         ierr = (*link->refinehook)(dm,*dmf,link->ctx);CHKERRQ(ierr);
1814       }
1815     }
1816   }
1817   ierr = PetscLogEventEnd(DM_Refine,dm,0,0,0);CHKERRQ(ierr);
1818   PetscFunctionReturn(0);
1819 }
1820 
1821 /*@C
1822    DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
1823 
1824    Logically Collective
1825 
1826    Input Arguments:
1827 +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
1828 .  refinehook - function to run when setting up a coarser level
1829 .  interphook - function to run to update data on finer levels (once per SNESSolve())
1830 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1831 
1832    Calling sequence of refinehook:
1833 $    refinehook(DM coarse,DM fine,void *ctx);
1834 
1835 +  coarse - coarse level DM
1836 .  fine - fine level DM to interpolate problem to
1837 -  ctx - optional user-defined function context
1838 
1839    Calling sequence for interphook:
1840 $    interphook(DM coarse,Mat interp,DM fine,void *ctx)
1841 
1842 +  coarse - coarse level DM
1843 .  interp - matrix interpolating a coarse-level solution to the finer grid
1844 .  fine - fine level DM to update
1845 -  ctx - optional user-defined function context
1846 
1847    Level: advanced
1848 
1849    Notes:
1850    This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
1851 
1852    If this function is called multiple times, the hooks will be run in the order they are added.
1853 
1854    This function is currently not available from Fortran.
1855 
1856 .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1857 @*/
1858 PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1859 {
1860   PetscErrorCode   ierr;
1861   DMRefineHookLink link,*p;
1862 
1863   PetscFunctionBegin;
1864   PetscValidHeaderSpecific(coarse,DM_CLASSID,1);
1865   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
1866     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(0);
1867   }
1868   ierr             = PetscNew(&link);CHKERRQ(ierr);
1869   link->refinehook = refinehook;
1870   link->interphook = interphook;
1871   link->ctx        = ctx;
1872   link->next       = NULL;
1873   *p               = link;
1874   PetscFunctionReturn(0);
1875 }
1876 
1877 /*@C
1878    DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
1879 
1880    Logically Collective
1881 
1882    Input Arguments:
1883 +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
1884 .  refinehook - function to run when setting up a coarser level
1885 .  interphook - function to run to update data on finer levels (once per SNESSolve())
1886 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1887 
1888    Level: advanced
1889 
1890    Notes:
1891    This function does nothing if the hook is not in the list.
1892 
1893    This function is currently not available from Fortran.
1894 
1895 .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1896 @*/
1897 PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1898 {
1899   PetscErrorCode   ierr;
1900   DMRefineHookLink link,*p;
1901 
1902   PetscFunctionBegin;
1903   PetscValidHeaderSpecific(coarse,DM_CLASSID,1);
1904   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
1905     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
1906       link = *p;
1907       *p = link->next;
1908       ierr = PetscFree(link);CHKERRQ(ierr);
1909       break;
1910     }
1911   }
1912   PetscFunctionReturn(0);
1913 }
1914 
1915 /*@
1916    DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
1917 
1918    Collective if any hooks are
1919 
1920    Input Arguments:
1921 +  coarse - coarser DM to use as a base
1922 .  interp - interpolation matrix, apply using MatInterpolate()
1923 -  fine - finer DM to update
1924 
1925    Level: developer
1926 
1927 .seealso: DMRefineHookAdd(), MatInterpolate()
1928 @*/
1929 PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1930 {
1931   PetscErrorCode   ierr;
1932   DMRefineHookLink link;
1933 
1934   PetscFunctionBegin;
1935   for (link=fine->refinehook; link; link=link->next) {
1936     if (link->interphook) {
1937       ierr = (*link->interphook)(coarse,interp,fine,link->ctx);CHKERRQ(ierr);
1938     }
1939   }
1940   PetscFunctionReturn(0);
1941 }
1942 
1943 /*@
1944     DMGetRefineLevel - Get's the number of refinements that have generated this DM.
1945 
1946     Not Collective
1947 
1948     Input Parameter:
1949 .   dm - the DM object
1950 
1951     Output Parameter:
1952 .   level - number of refinements
1953 
1954     Level: developer
1955 
1956 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1957 
1958 @*/
1959 PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1960 {
1961   PetscFunctionBegin;
1962   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1963   *level = dm->levelup;
1964   PetscFunctionReturn(0);
1965 }
1966 
1967 /*@
1968     DMSetRefineLevel - Set's the number of refinements that have generated this DM.
1969 
1970     Not Collective
1971 
1972     Input Parameter:
1973 +   dm - the DM object
1974 -   level - number of refinements
1975 
1976     Level: advanced
1977 
1978     Notes:
1979     This value is used by PCMG to determine how many multigrid levels to use
1980 
1981 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1982 
1983 @*/
1984 PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
1985 {
1986   PetscFunctionBegin;
1987   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1988   dm->levelup = level;
1989   PetscFunctionReturn(0);
1990 }
1991 
1992 /*@C
1993    DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
1994 
1995    Logically Collective
1996 
1997    Input Arguments:
1998 +  dm - the DM
1999 .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2000 .  endhook - function to run after DMGlobalToLocalEnd() has completed
2001 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2002 
2003    Calling sequence for beginhook:
2004 $    beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2005 
2006 +  dm - global DM
2007 .  g - global vector
2008 .  mode - mode
2009 .  l - local vector
2010 -  ctx - optional user-defined function context
2011 
2012 
2013    Calling sequence for endhook:
2014 $    endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2015 
2016 +  global - global DM
2017 -  ctx - optional user-defined function context
2018 
2019    Level: advanced
2020 
2021 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2022 @*/
2023 PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2024 {
2025   PetscErrorCode          ierr;
2026   DMGlobalToLocalHookLink link,*p;
2027 
2028   PetscFunctionBegin;
2029   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2030   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2031   ierr            = PetscNew(&link);CHKERRQ(ierr);
2032   link->beginhook = beginhook;
2033   link->endhook   = endhook;
2034   link->ctx       = ctx;
2035   link->next      = NULL;
2036   *p              = link;
2037   PetscFunctionReturn(0);
2038 }
2039 
2040 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2041 {
2042   Mat cMat;
2043   Vec cVec;
2044   PetscSection section, cSec;
2045   PetscInt pStart, pEnd, p, dof;
2046   PetscErrorCode ierr;
2047 
2048   PetscFunctionBegin;
2049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2050   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
2051   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2052     PetscInt nRows;
2053 
2054     ierr = MatGetSize(cMat,&nRows,NULL);CHKERRQ(ierr);
2055     if (nRows <= 0) PetscFunctionReturn(0);
2056     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
2057     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
2058     ierr = MatMult(cMat,l,cVec);CHKERRQ(ierr);
2059     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
2060     for (p = pStart; p < pEnd; p++) {
2061       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
2062       if (dof) {
2063         PetscScalar *vals;
2064         ierr = VecGetValuesSection(cVec,cSec,p,&vals);CHKERRQ(ierr);
2065         ierr = VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);CHKERRQ(ierr);
2066       }
2067     }
2068     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
2069   }
2070   PetscFunctionReturn(0);
2071 }
2072 
2073 /*@
2074     DMGlobalToLocalBegin - Begins updating local vectors from global vector
2075 
2076     Neighbor-wise Collective on DM
2077 
2078     Input Parameters:
2079 +   dm - the DM object
2080 .   g - the global vector
2081 .   mode - INSERT_VALUES or ADD_VALUES
2082 -   l - the local vector
2083 
2084 
2085     Level: beginner
2086 
2087 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2088 
2089 @*/
2090 PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2091 {
2092   PetscSF                 sf;
2093   PetscErrorCode          ierr;
2094   DMGlobalToLocalHookLink link;
2095 
2096   PetscFunctionBegin;
2097   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2098   for (link=dm->gtolhook; link; link=link->next) {
2099     if (link->beginhook) {
2100       ierr = (*link->beginhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);
2101     }
2102   }
2103   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
2104   if (sf) {
2105     const PetscScalar *gArray;
2106     PetscScalar       *lArray;
2107 
2108     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2109     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
2110     ierr = VecGetArrayRead(g, &gArray);CHKERRQ(ierr);
2111     ierr = PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
2112     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
2113     ierr = VecRestoreArrayRead(g, &gArray);CHKERRQ(ierr);
2114   } else {
2115     ierr = (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2116   }
2117   PetscFunctionReturn(0);
2118 }
2119 
2120 /*@
2121     DMGlobalToLocalEnd - Ends updating local vectors from global vector
2122 
2123     Neighbor-wise Collective on DM
2124 
2125     Input Parameters:
2126 +   dm - the DM object
2127 .   g - the global vector
2128 .   mode - INSERT_VALUES or ADD_VALUES
2129 -   l - the local vector
2130 
2131 
2132     Level: beginner
2133 
2134 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2135 
2136 @*/
2137 PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2138 {
2139   PetscSF                 sf;
2140   PetscErrorCode          ierr;
2141   const PetscScalar      *gArray;
2142   PetscScalar            *lArray;
2143   DMGlobalToLocalHookLink link;
2144 
2145   PetscFunctionBegin;
2146   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2147   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
2148   if (sf) {
2149     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2150 
2151     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
2152     ierr = VecGetArrayRead(g, &gArray);CHKERRQ(ierr);
2153     ierr = PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
2154     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
2155     ierr = VecRestoreArrayRead(g, &gArray);CHKERRQ(ierr);
2156   } else {
2157     ierr = (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2158   }
2159   ierr = DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);CHKERRQ(ierr);
2160   for (link=dm->gtolhook; link; link=link->next) {
2161     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
2162   }
2163   PetscFunctionReturn(0);
2164 }
2165 
2166 /*@C
2167    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2168 
2169    Logically Collective
2170 
2171    Input Arguments:
2172 +  dm - the DM
2173 .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2174 .  endhook - function to run after DMLocalToGlobalEnd() has completed
2175 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2176 
2177    Calling sequence for beginhook:
2178 $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2179 
2180 +  dm - global DM
2181 .  l - local vector
2182 .  mode - mode
2183 .  g - global vector
2184 -  ctx - optional user-defined function context
2185 
2186 
2187    Calling sequence for endhook:
2188 $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2189 
2190 +  global - global DM
2191 .  l - local vector
2192 .  mode - mode
2193 .  g - global vector
2194 -  ctx - optional user-defined function context
2195 
2196    Level: advanced
2197 
2198 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2199 @*/
2200 PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2201 {
2202   PetscErrorCode          ierr;
2203   DMLocalToGlobalHookLink link,*p;
2204 
2205   PetscFunctionBegin;
2206   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2207   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2208   ierr            = PetscNew(&link);CHKERRQ(ierr);
2209   link->beginhook = beginhook;
2210   link->endhook   = endhook;
2211   link->ctx       = ctx;
2212   link->next      = NULL;
2213   *p              = link;
2214   PetscFunctionReturn(0);
2215 }
2216 
2217 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2218 {
2219   Mat cMat;
2220   Vec cVec;
2221   PetscSection section, cSec;
2222   PetscInt pStart, pEnd, p, dof;
2223   PetscErrorCode ierr;
2224 
2225   PetscFunctionBegin;
2226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2227   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
2228   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2229     PetscInt nRows;
2230 
2231     ierr = MatGetSize(cMat,&nRows,NULL);CHKERRQ(ierr);
2232     if (nRows <= 0) PetscFunctionReturn(0);
2233     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
2234     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
2235     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
2236     for (p = pStart; p < pEnd; p++) {
2237       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
2238       if (dof) {
2239         PetscInt d;
2240         PetscScalar *vals;
2241         ierr = VecGetValuesSection(l,section,p,&vals);CHKERRQ(ierr);
2242         ierr = VecSetValuesSection(cVec,cSec,p,vals,mode);CHKERRQ(ierr);
2243         /* for this to be the true transpose, we have to zero the values that
2244          * we just extracted */
2245         for (d = 0; d < dof; d++) {
2246           vals[d] = 0.;
2247         }
2248       }
2249     }
2250     ierr = MatMultTransposeAdd(cMat,cVec,l,l);CHKERRQ(ierr);
2251     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
2252   }
2253   PetscFunctionReturn(0);
2254 }
2255 
2256 /*@
2257     DMLocalToGlobalBegin - updates global vectors from local vectors
2258 
2259     Neighbor-wise Collective on DM
2260 
2261     Input Parameters:
2262 +   dm - the DM object
2263 .   l - the local vector
2264 .   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.
2265 -   g - the global vector
2266 
2267     Notes:
2268     In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2269            INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2270 
2271     Level: beginner
2272 
2273 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2274 
2275 @*/
2276 PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2277 {
2278   PetscSF                 sf;
2279   PetscSection            s, gs;
2280   DMLocalToGlobalHookLink link;
2281   const PetscScalar      *lArray;
2282   PetscScalar            *gArray;
2283   PetscBool               isInsert;
2284   PetscErrorCode          ierr;
2285 
2286   PetscFunctionBegin;
2287   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2288   for (link=dm->ltoghook; link; link=link->next) {
2289     if (link->beginhook) {
2290       ierr = (*link->beginhook)(dm,l,mode,g,link->ctx);CHKERRQ(ierr);
2291     }
2292   }
2293   ierr = DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);CHKERRQ(ierr);
2294   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
2295   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
2296   switch (mode) {
2297   case INSERT_VALUES:
2298   case INSERT_ALL_VALUES:
2299   case INSERT_BC_VALUES:
2300     isInsert = PETSC_TRUE; break;
2301   case ADD_VALUES:
2302   case ADD_ALL_VALUES:
2303   case ADD_BC_VALUES:
2304     isInsert = PETSC_FALSE; break;
2305   default:
2306     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2307   }
2308   if (sf && !isInsert) {
2309     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
2310     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
2311     ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);CHKERRQ(ierr);
2312     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
2313     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2314   } else if (s && isInsert) {
2315     PetscInt gStart, pStart, pEnd, p;
2316 
2317     ierr = DMGetDefaultGlobalSection(dm, &gs);CHKERRQ(ierr);
2318     ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
2319     ierr = VecGetOwnershipRange(g, &gStart, NULL);CHKERRQ(ierr);
2320     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
2321     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
2322     for (p = pStart; p < pEnd; ++p) {
2323       PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2324 
2325       ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
2326       ierr = PetscSectionGetDof(gs, p, &gdof);CHKERRQ(ierr);
2327       ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2328       ierr = PetscSectionGetConstraintDof(gs, p, &gcdof);CHKERRQ(ierr);
2329       ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
2330       ierr = PetscSectionGetOffset(gs, p, &goff);CHKERRQ(ierr);
2331       /* Ignore off-process data and points with no global data */
2332       if (!gdof || goff < 0) continue;
2333       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);
2334       /* If no constraints are enforced in the global vector */
2335       if (!gcdof) {
2336         for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2337       /* If constraints are enforced in the global vector */
2338       } else if (cdof == gcdof) {
2339         const PetscInt *cdofs;
2340         PetscInt        cind = 0;
2341 
2342         ierr = PetscSectionGetConstraintIndices(s, p, &cdofs);CHKERRQ(ierr);
2343         for (d = 0, e = 0; d < dof; ++d) {
2344           if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2345           gArray[goff-gStart+e++] = lArray[off+d];
2346         }
2347       } 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);
2348     }
2349     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
2350     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2351   } else {
2352     ierr = (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
2353   }
2354   PetscFunctionReturn(0);
2355 }
2356 
2357 /*@
2358     DMLocalToGlobalEnd - updates global vectors from local vectors
2359 
2360     Neighbor-wise Collective on DM
2361 
2362     Input Parameters:
2363 +   dm - the DM object
2364 .   l - the local vector
2365 .   mode - INSERT_VALUES or ADD_VALUES
2366 -   g - the global vector
2367 
2368 
2369     Level: beginner
2370 
2371 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2372 
2373 @*/
2374 PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2375 {
2376   PetscSF                 sf;
2377   PetscSection            s;
2378   DMLocalToGlobalHookLink link;
2379   PetscBool               isInsert;
2380   PetscErrorCode          ierr;
2381 
2382   PetscFunctionBegin;
2383   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2384   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
2385   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
2386   switch (mode) {
2387   case INSERT_VALUES:
2388   case INSERT_ALL_VALUES:
2389     isInsert = PETSC_TRUE; break;
2390   case ADD_VALUES:
2391   case ADD_ALL_VALUES:
2392     isInsert = PETSC_FALSE; break;
2393   default:
2394     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2395   }
2396   if (sf && !isInsert) {
2397     const PetscScalar *lArray;
2398     PetscScalar       *gArray;
2399 
2400     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
2401     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
2402     ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);CHKERRQ(ierr);
2403     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
2404     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2405   } else if (s && isInsert) {
2406   } else {
2407     ierr = (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
2408   }
2409   for (link=dm->ltoghook; link; link=link->next) {
2410     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
2411   }
2412   PetscFunctionReturn(0);
2413 }
2414 
2415 /*@
2416    DMLocalToLocalBegin - Maps from a local vector (including ghost points
2417    that contain irrelevant values) to another local vector where the ghost
2418    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2419 
2420    Neighbor-wise Collective on DM and Vec
2421 
2422    Input Parameters:
2423 +  dm - the DM object
2424 .  g - the original local vector
2425 -  mode - one of INSERT_VALUES or ADD_VALUES
2426 
2427    Output Parameter:
2428 .  l  - the local vector with correct ghost values
2429 
2430    Level: intermediate
2431 
2432    Notes:
2433    The local vectors used here need not be the same as those
2434    obtained from DMCreateLocalVector(), BUT they
2435    must have the same parallel data layout; they could, for example, be
2436    obtained with VecDuplicate() from the DM originating vectors.
2437 
2438 .keywords: DM, local-to-local, begin
2439 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2440 
2441 @*/
2442 PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2443 {
2444   PetscErrorCode          ierr;
2445 
2446   PetscFunctionBegin;
2447   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2448   if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2449   ierr = (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2450   PetscFunctionReturn(0);
2451 }
2452 
2453 /*@
2454    DMLocalToLocalEnd - Maps from a local vector (including ghost points
2455    that contain irrelevant values) to another local vector where the ghost
2456    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2457 
2458    Neighbor-wise Collective on DM and Vec
2459 
2460    Input Parameters:
2461 +  da - the DM object
2462 .  g - the original local vector
2463 -  mode - one of INSERT_VALUES or ADD_VALUES
2464 
2465    Output Parameter:
2466 .  l  - the local vector with correct ghost values
2467 
2468    Level: intermediate
2469 
2470    Notes:
2471    The local vectors used here need not be the same as those
2472    obtained from DMCreateLocalVector(), BUT they
2473    must have the same parallel data layout; they could, for example, be
2474    obtained with VecDuplicate() from the DM originating vectors.
2475 
2476 .keywords: DM, local-to-local, end
2477 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2478 
2479 @*/
2480 PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2481 {
2482   PetscErrorCode          ierr;
2483 
2484   PetscFunctionBegin;
2485   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2486   if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2487   ierr = (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2488   PetscFunctionReturn(0);
2489 }
2490 
2491 
2492 /*@
2493     DMCoarsen - Coarsens a DM object
2494 
2495     Collective on DM
2496 
2497     Input Parameter:
2498 +   dm - the DM object
2499 -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2500 
2501     Output Parameter:
2502 .   dmc - the coarsened DM
2503 
2504     Level: developer
2505 
2506 .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2507 
2508 @*/
2509 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2510 {
2511   PetscErrorCode    ierr;
2512   DMCoarsenHookLink link;
2513 
2514   PetscFunctionBegin;
2515   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2516   if (!dm->ops->coarsen) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot coarsen");
2517   ierr = PetscLogEventBegin(DM_Coarsen,dm,0,0,0);CHKERRQ(ierr);
2518   ierr                      = (*dm->ops->coarsen)(dm, comm, dmc);CHKERRQ(ierr);
2519   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2520   ierr = DMSetCoarseDM(dm,*dmc);CHKERRQ(ierr);
2521   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2522   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
2523   (*dmc)->ctx               = dm->ctx;
2524   (*dmc)->levelup           = dm->levelup;
2525   (*dmc)->leveldown         = dm->leveldown + 1;
2526   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
2527   for (link=dm->coarsenhook; link; link=link->next) {
2528     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
2529   }
2530   ierr = PetscLogEventEnd(DM_Coarsen,dm,0,0,0);CHKERRQ(ierr);
2531   PetscFunctionReturn(0);
2532 }
2533 
2534 /*@C
2535    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2536 
2537    Logically Collective
2538 
2539    Input Arguments:
2540 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2541 .  coarsenhook - function to run when setting up a coarser level
2542 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2543 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2544 
2545    Calling sequence of coarsenhook:
2546 $    coarsenhook(DM fine,DM coarse,void *ctx);
2547 
2548 +  fine - fine level DM
2549 .  coarse - coarse level DM to restrict problem to
2550 -  ctx - optional user-defined function context
2551 
2552    Calling sequence for restricthook:
2553 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2554 
2555 +  fine - fine level DM
2556 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2557 .  rscale - scaling vector for restriction
2558 .  inject - matrix restricting by injection
2559 .  coarse - coarse level DM to update
2560 -  ctx - optional user-defined function context
2561 
2562    Level: advanced
2563 
2564    Notes:
2565    This function is only needed if auxiliary data needs to be set up on coarse grids.
2566 
2567    If this function is called multiple times, the hooks will be run in the order they are added.
2568 
2569    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2570    extract the finest level information from its context (instead of from the SNES).
2571 
2572    This function is currently not available from Fortran.
2573 
2574 .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2575 @*/
2576 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2577 {
2578   PetscErrorCode    ierr;
2579   DMCoarsenHookLink link,*p;
2580 
2581   PetscFunctionBegin;
2582   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2583   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2584     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0);
2585   }
2586   ierr               = PetscNew(&link);CHKERRQ(ierr);
2587   link->coarsenhook  = coarsenhook;
2588   link->restricthook = restricthook;
2589   link->ctx          = ctx;
2590   link->next         = NULL;
2591   *p                 = link;
2592   PetscFunctionReturn(0);
2593 }
2594 
2595 /*@C
2596    DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
2597 
2598    Logically Collective
2599 
2600    Input Arguments:
2601 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2602 .  coarsenhook - function to run when setting up a coarser level
2603 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2604 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2605 
2606    Level: advanced
2607 
2608    Notes:
2609    This function does nothing if the hook is not in the list.
2610 
2611    This function is currently not available from Fortran.
2612 
2613 .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2614 @*/
2615 PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2616 {
2617   PetscErrorCode    ierr;
2618   DMCoarsenHookLink link,*p;
2619 
2620   PetscFunctionBegin;
2621   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2622   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2623     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2624       link = *p;
2625       *p = link->next;
2626       ierr = PetscFree(link);CHKERRQ(ierr);
2627       break;
2628     }
2629   }
2630   PetscFunctionReturn(0);
2631 }
2632 
2633 
2634 /*@
2635    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2636 
2637    Collective if any hooks are
2638 
2639    Input Arguments:
2640 +  fine - finer DM to use as a base
2641 .  restrct - restriction matrix, apply using MatRestrict()
2642 .  rscale - scaling vector for restriction
2643 .  inject - injection matrix, also use MatRestrict()
2644 -  coarse - coarser DM to update
2645 
2646    Level: developer
2647 
2648 .seealso: DMCoarsenHookAdd(), MatRestrict()
2649 @*/
2650 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2651 {
2652   PetscErrorCode    ierr;
2653   DMCoarsenHookLink link;
2654 
2655   PetscFunctionBegin;
2656   for (link=fine->coarsenhook; link; link=link->next) {
2657     if (link->restricthook) {
2658       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2659     }
2660   }
2661   PetscFunctionReturn(0);
2662 }
2663 
2664 /*@C
2665    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2666 
2667    Logically Collective
2668 
2669    Input Arguments:
2670 +  global - global DM
2671 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2672 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2673 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2674 
2675 
2676    Calling sequence for ddhook:
2677 $    ddhook(DM global,DM block,void *ctx)
2678 
2679 +  global - global DM
2680 .  block  - block DM
2681 -  ctx - optional user-defined function context
2682 
2683    Calling sequence for restricthook:
2684 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2685 
2686 +  global - global DM
2687 .  out    - scatter to the outer (with ghost and overlap points) block vector
2688 .  in     - scatter to block vector values only owned locally
2689 .  block  - block DM
2690 -  ctx - optional user-defined function context
2691 
2692    Level: advanced
2693 
2694    Notes:
2695    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2696 
2697    If this function is called multiple times, the hooks will be run in the order they are added.
2698 
2699    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2700    extract the global information from its context (instead of from the SNES).
2701 
2702    This function is currently not available from Fortran.
2703 
2704 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2705 @*/
2706 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2707 {
2708   PetscErrorCode      ierr;
2709   DMSubDomainHookLink link,*p;
2710 
2711   PetscFunctionBegin;
2712   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2713   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2714     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0);
2715   }
2716   ierr               = PetscNew(&link);CHKERRQ(ierr);
2717   link->restricthook = restricthook;
2718   link->ddhook       = ddhook;
2719   link->ctx          = ctx;
2720   link->next         = NULL;
2721   *p                 = link;
2722   PetscFunctionReturn(0);
2723 }
2724 
2725 /*@C
2726    DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
2727 
2728    Logically Collective
2729 
2730    Input Arguments:
2731 +  global - global DM
2732 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2733 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2734 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2735 
2736    Level: advanced
2737 
2738    Notes:
2739 
2740    This function is currently not available from Fortran.
2741 
2742 .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2743 @*/
2744 PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2745 {
2746   PetscErrorCode      ierr;
2747   DMSubDomainHookLink link,*p;
2748 
2749   PetscFunctionBegin;
2750   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2751   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2752     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2753       link = *p;
2754       *p = link->next;
2755       ierr = PetscFree(link);CHKERRQ(ierr);
2756       break;
2757     }
2758   }
2759   PetscFunctionReturn(0);
2760 }
2761 
2762 /*@
2763    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2764 
2765    Collective if any hooks are
2766 
2767    Input Arguments:
2768 +  fine - finer DM to use as a base
2769 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2770 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2771 -  coarse - coarer DM to update
2772 
2773    Level: developer
2774 
2775 .seealso: DMCoarsenHookAdd(), MatRestrict()
2776 @*/
2777 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2778 {
2779   PetscErrorCode      ierr;
2780   DMSubDomainHookLink link;
2781 
2782   PetscFunctionBegin;
2783   for (link=global->subdomainhook; link; link=link->next) {
2784     if (link->restricthook) {
2785       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2786     }
2787   }
2788   PetscFunctionReturn(0);
2789 }
2790 
2791 /*@
2792     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2793 
2794     Not Collective
2795 
2796     Input Parameter:
2797 .   dm - the DM object
2798 
2799     Output Parameter:
2800 .   level - number of coarsenings
2801 
2802     Level: developer
2803 
2804 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2805 
2806 @*/
2807 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2808 {
2809   PetscFunctionBegin;
2810   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2811   *level = dm->leveldown;
2812   PetscFunctionReturn(0);
2813 }
2814 
2815 
2816 
2817 /*@C
2818     DMRefineHierarchy - Refines a DM object, all levels at once
2819 
2820     Collective on DM
2821 
2822     Input Parameter:
2823 +   dm - the DM object
2824 -   nlevels - the number of levels of refinement
2825 
2826     Output Parameter:
2827 .   dmf - the refined DM hierarchy
2828 
2829     Level: developer
2830 
2831 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2832 
2833 @*/
2834 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2835 {
2836   PetscErrorCode ierr;
2837 
2838   PetscFunctionBegin;
2839   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2840   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2841   if (nlevels == 0) PetscFunctionReturn(0);
2842   if (dm->ops->refinehierarchy) {
2843     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2844   } else if (dm->ops->refine) {
2845     PetscInt i;
2846 
2847     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2848     for (i=1; i<nlevels; i++) {
2849       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2850     }
2851   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2852   PetscFunctionReturn(0);
2853 }
2854 
2855 /*@C
2856     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2857 
2858     Collective on DM
2859 
2860     Input Parameter:
2861 +   dm - the DM object
2862 -   nlevels - the number of levels of coarsening
2863 
2864     Output Parameter:
2865 .   dmc - the coarsened DM hierarchy
2866 
2867     Level: developer
2868 
2869 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2870 
2871 @*/
2872 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2873 {
2874   PetscErrorCode ierr;
2875 
2876   PetscFunctionBegin;
2877   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2878   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2879   if (nlevels == 0) PetscFunctionReturn(0);
2880   PetscValidPointer(dmc,3);
2881   if (dm->ops->coarsenhierarchy) {
2882     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2883   } else if (dm->ops->coarsen) {
2884     PetscInt i;
2885 
2886     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2887     for (i=1; i<nlevels; i++) {
2888       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2889     }
2890   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2891   PetscFunctionReturn(0);
2892 }
2893 
2894 /*@
2895    DMCreateAggregates - Gets the aggregates that map between
2896    grids associated with two DMs.
2897 
2898    Collective on DM
2899 
2900    Input Parameters:
2901 +  dmc - the coarse grid DM
2902 -  dmf - the fine grid DM
2903 
2904    Output Parameters:
2905 .  rest - the restriction matrix (transpose of the projection matrix)
2906 
2907    Level: intermediate
2908 
2909 .keywords: interpolation, restriction, multigrid
2910 
2911 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2912 @*/
2913 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2914 {
2915   PetscErrorCode ierr;
2916 
2917   PetscFunctionBegin;
2918   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2919   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2920   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2921   PetscFunctionReturn(0);
2922 }
2923 
2924 /*@C
2925     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2926 
2927     Not Collective
2928 
2929     Input Parameters:
2930 +   dm - the DM object
2931 -   destroy - the destroy function
2932 
2933     Level: intermediate
2934 
2935 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2936 
2937 @*/
2938 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2939 {
2940   PetscFunctionBegin;
2941   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2942   dm->ctxdestroy = destroy;
2943   PetscFunctionReturn(0);
2944 }
2945 
2946 /*@
2947     DMSetApplicationContext - Set a user context into a DM object
2948 
2949     Not Collective
2950 
2951     Input Parameters:
2952 +   dm - the DM object
2953 -   ctx - the user context
2954 
2955     Level: intermediate
2956 
2957 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2958 
2959 @*/
2960 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2961 {
2962   PetscFunctionBegin;
2963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2964   dm->ctx = ctx;
2965   PetscFunctionReturn(0);
2966 }
2967 
2968 /*@
2969     DMGetApplicationContext - Gets a user context from a DM object
2970 
2971     Not Collective
2972 
2973     Input Parameter:
2974 .   dm - the DM object
2975 
2976     Output Parameter:
2977 .   ctx - the user context
2978 
2979     Level: intermediate
2980 
2981 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2982 
2983 @*/
2984 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2985 {
2986   PetscFunctionBegin;
2987   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2988   *(void**)ctx = dm->ctx;
2989   PetscFunctionReturn(0);
2990 }
2991 
2992 /*@C
2993     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2994 
2995     Logically Collective on DM
2996 
2997     Input Parameter:
2998 +   dm - the DM object
2999 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3000 
3001     Level: intermediate
3002 
3003 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3004          DMSetJacobian()
3005 
3006 @*/
3007 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3008 {
3009   PetscFunctionBegin;
3010   dm->ops->computevariablebounds = f;
3011   PetscFunctionReturn(0);
3012 }
3013 
3014 /*@
3015     DMHasVariableBounds - does the DM object have a variable bounds function?
3016 
3017     Not Collective
3018 
3019     Input Parameter:
3020 .   dm - the DM object to destroy
3021 
3022     Output Parameter:
3023 .   flg - PETSC_TRUE if the variable bounds function exists
3024 
3025     Level: developer
3026 
3027 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3028 
3029 @*/
3030 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
3031 {
3032   PetscFunctionBegin;
3033   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3034   PetscFunctionReturn(0);
3035 }
3036 
3037 /*@C
3038     DMComputeVariableBounds - compute variable bounds used by SNESVI.
3039 
3040     Logically Collective on DM
3041 
3042     Input Parameters:
3043 .   dm - the DM object
3044 
3045     Output parameters:
3046 +   xl - lower bound
3047 -   xu - upper bound
3048 
3049     Level: advanced
3050 
3051     Notes:
3052     This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3053 
3054 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3055 
3056 @*/
3057 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3058 {
3059   PetscErrorCode ierr;
3060 
3061   PetscFunctionBegin;
3062   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
3063   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
3064   if (dm->ops->computevariablebounds) {
3065     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
3066   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
3067   PetscFunctionReturn(0);
3068 }
3069 
3070 /*@
3071     DMHasColoring - does the DM object have a method of providing a coloring?
3072 
3073     Not Collective
3074 
3075     Input Parameter:
3076 .   dm - the DM object
3077 
3078     Output Parameter:
3079 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3080 
3081     Level: developer
3082 
3083 .seealso DMHasFunction(), DMCreateColoring()
3084 
3085 @*/
3086 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
3087 {
3088   PetscFunctionBegin;
3089   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3090   PetscFunctionReturn(0);
3091 }
3092 
3093 /*@
3094     DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3095 
3096     Not Collective
3097 
3098     Input Parameter:
3099 .   dm - the DM object
3100 
3101     Output Parameter:
3102 .   flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3103 
3104     Level: developer
3105 
3106 .seealso DMHasFunction(), DMCreateRestriction()
3107 
3108 @*/
3109 PetscErrorCode  DMHasCreateRestriction(DM dm,PetscBool  *flg)
3110 {
3111   PetscFunctionBegin;
3112   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3113   PetscFunctionReturn(0);
3114 }
3115 
3116 
3117 /*@
3118     DMHasCreateInjection - does the DM object have a method of providing an injection?
3119 
3120     Not Collective
3121 
3122     Input Parameter:
3123 .   dm - the DM object
3124 
3125     Output Parameter:
3126 .   flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3127 
3128     Level: developer
3129 
3130 .seealso DMHasFunction(), DMCreateInjection()
3131 
3132 @*/
3133 PetscErrorCode  DMHasCreateInjection(DM dm,PetscBool  *flg)
3134 {
3135   PetscErrorCode ierr;
3136   PetscFunctionBegin;
3137   if (!dm->ops->hascreateinjection) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DMHasCreateInjection not implemented for this type");
3138   ierr = (*dm->ops->hascreateinjection)(dm,flg);CHKERRQ(ierr);
3139   PetscFunctionReturn(0);
3140 }
3141 
3142 /*@C
3143     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
3144 
3145     Collective on DM
3146 
3147     Input Parameter:
3148 +   dm - the DM object
3149 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
3150 
3151     Level: developer
3152 
3153 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3154 
3155 @*/
3156 PetscErrorCode  DMSetVec(DM dm,Vec x)
3157 {
3158   PetscErrorCode ierr;
3159 
3160   PetscFunctionBegin;
3161   if (x) {
3162     if (!dm->x) {
3163       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
3164     }
3165     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
3166   } else if (dm->x) {
3167     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
3168   }
3169   PetscFunctionReturn(0);
3170 }
3171 
3172 PetscFunctionList DMList              = NULL;
3173 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3174 
3175 /*@C
3176   DMSetType - Builds a DM, for a particular DM implementation.
3177 
3178   Collective on DM
3179 
3180   Input Parameters:
3181 + dm     - The DM object
3182 - method - The name of the DM type
3183 
3184   Options Database Key:
3185 . -dm_type <type> - Sets the DM type; use -help for a list of available types
3186 
3187   Notes:
3188   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3189 
3190   Level: intermediate
3191 
3192 .keywords: DM, set, type
3193 .seealso: DMGetType(), DMCreate()
3194 @*/
3195 PetscErrorCode  DMSetType(DM dm, DMType method)
3196 {
3197   PetscErrorCode (*r)(DM);
3198   PetscBool      match;
3199   PetscErrorCode ierr;
3200 
3201   PetscFunctionBegin;
3202   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
3203   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
3204   if (match) PetscFunctionReturn(0);
3205 
3206   ierr = DMRegisterAll();CHKERRQ(ierr);
3207   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
3208   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3209 
3210   if (dm->ops->destroy) {
3211     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
3212     dm->ops->destroy = NULL;
3213   }
3214   ierr = (*r)(dm);CHKERRQ(ierr);
3215   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
3216   PetscFunctionReturn(0);
3217 }
3218 
3219 /*@C
3220   DMGetType - Gets the DM type name (as a string) from the DM.
3221 
3222   Not Collective
3223 
3224   Input Parameter:
3225 . dm  - The DM
3226 
3227   Output Parameter:
3228 . type - The DM type name
3229 
3230   Level: intermediate
3231 
3232 .keywords: DM, get, type, name
3233 .seealso: DMSetType(), DMCreate()
3234 @*/
3235 PetscErrorCode  DMGetType(DM dm, DMType *type)
3236 {
3237   PetscErrorCode ierr;
3238 
3239   PetscFunctionBegin;
3240   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
3241   PetscValidPointer(type,2);
3242   ierr = DMRegisterAll();CHKERRQ(ierr);
3243   *type = ((PetscObject)dm)->type_name;
3244   PetscFunctionReturn(0);
3245 }
3246 
3247 /*@C
3248   DMConvert - Converts a DM to another DM, either of the same or different type.
3249 
3250   Collective on DM
3251 
3252   Input Parameters:
3253 + dm - the DM
3254 - newtype - new DM type (use "same" for the same type)
3255 
3256   Output Parameter:
3257 . M - pointer to new DM
3258 
3259   Notes:
3260   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3261   the MPI communicator of the generated DM is always the same as the communicator
3262   of the input DM.
3263 
3264   Level: intermediate
3265 
3266 .seealso: DMCreate()
3267 @*/
3268 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3269 {
3270   DM             B;
3271   char           convname[256];
3272   PetscBool      sametype/*, issame */;
3273   PetscErrorCode ierr;
3274 
3275   PetscFunctionBegin;
3276   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3277   PetscValidType(dm,1);
3278   PetscValidPointer(M,3);
3279   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
3280   /* ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr); */
3281   if (sametype) {
3282     *M   = dm;
3283     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
3284     PetscFunctionReturn(0);
3285   } else {
3286     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3287 
3288     /*
3289        Order of precedence:
3290        1) See if a specialized converter is known to the current DM.
3291        2) See if a specialized converter is known to the desired DM class.
3292        3) See if a good general converter is registered for the desired class
3293        4) See if a good general converter is known for the current matrix.
3294        5) Use a really basic converter.
3295     */
3296 
3297     /* 1) See if a specialized converter is known to the current DM and the desired class */
3298     ierr = PetscStrncpy(convname,"DMConvert_",sizeof(convname));CHKERRQ(ierr);
3299     ierr = PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));CHKERRQ(ierr);
3300     ierr = PetscStrlcat(convname,"_",sizeof(convname));CHKERRQ(ierr);
3301     ierr = PetscStrlcat(convname,newtype,sizeof(convname));CHKERRQ(ierr);
3302     ierr = PetscStrlcat(convname,"_C",sizeof(convname));CHKERRQ(ierr);
3303     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
3304     if (conv) goto foundconv;
3305 
3306     /* 2)  See if a specialized converter is known to the desired DM class. */
3307     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
3308     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
3309     ierr = PetscStrncpy(convname,"DMConvert_",sizeof(convname));CHKERRQ(ierr);
3310     ierr = PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));CHKERRQ(ierr);
3311     ierr = PetscStrlcat(convname,"_",sizeof(convname));CHKERRQ(ierr);
3312     ierr = PetscStrlcat(convname,newtype,sizeof(convname));CHKERRQ(ierr);
3313     ierr = PetscStrlcat(convname,"_C",sizeof(convname));CHKERRQ(ierr);
3314     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
3315     if (conv) {
3316       ierr = DMDestroy(&B);CHKERRQ(ierr);
3317       goto foundconv;
3318     }
3319 
3320 #if 0
3321     /* 3) See if a good general converter is registered for the desired class */
3322     conv = B->ops->convertfrom;
3323     ierr = DMDestroy(&B);CHKERRQ(ierr);
3324     if (conv) goto foundconv;
3325 
3326     /* 4) See if a good general converter is known for the current matrix */
3327     if (dm->ops->convert) {
3328       conv = dm->ops->convert;
3329     }
3330     if (conv) goto foundconv;
3331 #endif
3332 
3333     /* 5) Use a really basic converter. */
3334     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3335 
3336 foundconv:
3337     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
3338     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
3339     /* Things that are independent of DM type: We should consult DMClone() here */
3340     {
3341       PetscBool             isper;
3342       const PetscReal      *maxCell, *L;
3343       const DMBoundaryType *bd;
3344       ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
3345       ierr = DMSetPeriodicity(*M, isper, maxCell,  L,  bd);CHKERRQ(ierr);
3346     }
3347     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
3348   }
3349   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
3350   PetscFunctionReturn(0);
3351 }
3352 
3353 /*--------------------------------------------------------------------------------------------------------------------*/
3354 
3355 /*@C
3356   DMRegister -  Adds a new DM component implementation
3357 
3358   Not Collective
3359 
3360   Input Parameters:
3361 + name        - The name of a new user-defined creation routine
3362 - create_func - The creation routine itself
3363 
3364   Notes:
3365   DMRegister() may be called multiple times to add several user-defined DMs
3366 
3367 
3368   Sample usage:
3369 .vb
3370     DMRegister("my_da", MyDMCreate);
3371 .ve
3372 
3373   Then, your DM type can be chosen with the procedural interface via
3374 .vb
3375     DMCreate(MPI_Comm, DM *);
3376     DMSetType(DM,"my_da");
3377 .ve
3378    or at runtime via the option
3379 .vb
3380     -da_type my_da
3381 .ve
3382 
3383   Level: advanced
3384 
3385 .keywords: DM, register
3386 .seealso: DMRegisterAll(), DMRegisterDestroy()
3387 
3388 @*/
3389 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3390 {
3391   PetscErrorCode ierr;
3392 
3393   PetscFunctionBegin;
3394   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
3395   PetscFunctionReturn(0);
3396 }
3397 
3398 /*@C
3399   DMLoad - Loads a DM that has been stored in binary  with DMView().
3400 
3401   Collective on PetscViewer
3402 
3403   Input Parameters:
3404 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3405            some related function before a call to DMLoad().
3406 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3407            HDF5 file viewer, obtained from PetscViewerHDF5Open()
3408 
3409    Level: intermediate
3410 
3411   Notes:
3412    The type is determined by the data in the file, any type set into the DM before this call is ignored.
3413 
3414   Notes for advanced users:
3415   Most users should not need to know the details of the binary storage
3416   format, since DMLoad() and DMView() completely hide these details.
3417   But for anyone who's interested, the standard binary matrix storage
3418   format is
3419 .vb
3420      has not yet been determined
3421 .ve
3422 
3423 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3424 @*/
3425 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3426 {
3427   PetscBool      isbinary, ishdf5;
3428   PetscErrorCode ierr;
3429 
3430   PetscFunctionBegin;
3431   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
3432   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3433   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
3434   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
3435   if (isbinary) {
3436     PetscInt classid;
3437     char     type[256];
3438 
3439     ierr = PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);CHKERRQ(ierr);
3440     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3441     ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
3442     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
3443     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3444   } else if (ishdf5) {
3445     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3446   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3447   PetscFunctionReturn(0);
3448 }
3449 
3450 /******************************** FEM Support **********************************/
3451 
3452 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3453 {
3454   PetscInt       f;
3455   PetscErrorCode ierr;
3456 
3457   PetscFunctionBegin;
3458   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3459   for (f = 0; f < len; ++f) {
3460     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3461   }
3462   PetscFunctionReturn(0);
3463 }
3464 
3465 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3466 {
3467   PetscInt       f, g;
3468   PetscErrorCode ierr;
3469 
3470   PetscFunctionBegin;
3471   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3472   for (f = 0; f < rows; ++f) {
3473     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3474     for (g = 0; g < cols; ++g) {
3475       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3476     }
3477     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3478   }
3479   PetscFunctionReturn(0);
3480 }
3481 
3482 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3483 {
3484   PetscInt          localSize, bs;
3485   PetscMPIInt       size;
3486   Vec               x, xglob;
3487   const PetscScalar *xarray;
3488   PetscErrorCode    ierr;
3489 
3490   PetscFunctionBegin;
3491   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);CHKERRQ(ierr);
3492   ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3493   ierr = VecCopy(X, x);CHKERRQ(ierr);
3494   ierr = VecChop(x, tol);CHKERRQ(ierr);
3495   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);CHKERRQ(ierr);
3496   if (size > 1) {
3497     ierr = VecGetLocalSize(x,&localSize);CHKERRQ(ierr);
3498     ierr = VecGetArrayRead(x,&xarray);CHKERRQ(ierr);
3499     ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
3500     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);CHKERRQ(ierr);
3501   } else {
3502     xglob = x;
3503   }
3504   ierr = VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));CHKERRQ(ierr);
3505   if (size > 1) {
3506     ierr = VecDestroy(&xglob);CHKERRQ(ierr);
3507     ierr = VecRestoreArrayRead(x,&xarray);CHKERRQ(ierr);
3508   }
3509   ierr = VecDestroy(&x);CHKERRQ(ierr);
3510   PetscFunctionReturn(0);
3511 }
3512 
3513 /*@
3514   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
3515 
3516   Input Parameter:
3517 . dm - The DM
3518 
3519   Output Parameter:
3520 . section - The PetscSection
3521 
3522   Level: intermediate
3523 
3524   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3525 
3526 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3527 @*/
3528 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3529 {
3530   PetscErrorCode ierr;
3531 
3532   PetscFunctionBegin;
3533   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3534   PetscValidPointer(section, 2);
3535   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3536     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3537     if (dm->defaultSection) {ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);}
3538   }
3539   *section = dm->defaultSection;
3540   PetscFunctionReturn(0);
3541 }
3542 
3543 /*@
3544   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
3545 
3546   Input Parameters:
3547 + dm - The DM
3548 - section - The PetscSection
3549 
3550   Level: intermediate
3551 
3552   Note: Any existing Section will be destroyed
3553 
3554 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3555 @*/
3556 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3557 {
3558   PetscInt       numFields = 0;
3559   PetscInt       f;
3560   PetscErrorCode ierr;
3561 
3562   PetscFunctionBegin;
3563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3564   if (section) {
3565     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3566     ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3567   }
3568   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3569   dm->defaultSection = section;
3570   if (section) {ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);}
3571   if (numFields) {
3572     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3573     for (f = 0; f < numFields; ++f) {
3574       PetscObject disc;
3575       const char *name;
3576 
3577       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3578       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3579       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3580     }
3581   }
3582   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3583   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3584   PetscFunctionReturn(0);
3585 }
3586 
3587 /*@
3588   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3589 
3590   not collective
3591 
3592   Input Parameter:
3593 . dm - The DM
3594 
3595   Output Parameter:
3596 + 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.
3597 - 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.
3598 
3599   Level: advanced
3600 
3601   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3602 
3603 .seealso: DMSetDefaultConstraints()
3604 @*/
3605 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3606 {
3607   PetscErrorCode ierr;
3608 
3609   PetscFunctionBegin;
3610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3611   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3612   if (section) {*section = dm->defaultConstraintSection;}
3613   if (mat) {*mat = dm->defaultConstraintMat;}
3614   PetscFunctionReturn(0);
3615 }
3616 
3617 /*@
3618   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3619 
3620   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().
3621 
3622   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.
3623 
3624   collective on dm
3625 
3626   Input Parameters:
3627 + dm - The DM
3628 + 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).
3629 - 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).
3630 
3631   Level: advanced
3632 
3633   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3634 
3635 .seealso: DMGetDefaultConstraints()
3636 @*/
3637 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3638 {
3639   PetscMPIInt result;
3640   PetscErrorCode ierr;
3641 
3642   PetscFunctionBegin;
3643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3644   if (section) {
3645     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3646     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3647     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3648   }
3649   if (mat) {
3650     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3651     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3652     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3653   }
3654   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3655   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3656   dm->defaultConstraintSection = section;
3657   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3658   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3659   dm->defaultConstraintMat = mat;
3660   PetscFunctionReturn(0);
3661 }
3662 
3663 #if defined(PETSC_USE_DEBUG)
3664 /*
3665   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
3666 
3667   Input Parameters:
3668 + dm - The DM
3669 . localSection - PetscSection describing the local data layout
3670 - globalSection - PetscSection describing the global data layout
3671 
3672   Level: intermediate
3673 
3674 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3675 */
3676 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3677 {
3678   MPI_Comm        comm;
3679   PetscLayout     layout;
3680   const PetscInt *ranges;
3681   PetscInt        pStart, pEnd, p, nroots;
3682   PetscMPIInt     size, rank;
3683   PetscBool       valid = PETSC_TRUE, gvalid;
3684   PetscErrorCode  ierr;
3685 
3686   PetscFunctionBegin;
3687   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3689   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3690   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3691   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3692   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3693   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3694   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3695   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3696   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3697   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3698   for (p = pStart; p < pEnd; ++p) {
3699     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
3700 
3701     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3702     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3703     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3704     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3705     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3706     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3707     if (!gdof) continue; /* Censored point */
3708     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;}
3709     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;}
3710     if (gdof < 0) {
3711       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3712       for (d = 0; d < gsize; ++d) {
3713         PetscInt offset = -(goff+1) + d, r;
3714 
3715         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3716         if (r < 0) r = -(r+2);
3717         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;}
3718       }
3719     }
3720   }
3721   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3722   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
3723   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
3724   if (!gvalid) {
3725     ierr = DMView(dm, NULL);CHKERRQ(ierr);
3726     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3727   }
3728   PetscFunctionReturn(0);
3729 }
3730 #endif
3731 
3732 /*@
3733   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3734 
3735   Collective on DM
3736 
3737   Input Parameter:
3738 . dm - The DM
3739 
3740   Output Parameter:
3741 . section - The PetscSection
3742 
3743   Level: intermediate
3744 
3745   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3746 
3747 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3748 @*/
3749 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3750 {
3751   PetscErrorCode ierr;
3752 
3753   PetscFunctionBegin;
3754   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3755   PetscValidPointer(section, 2);
3756   if (!dm->defaultGlobalSection) {
3757     PetscSection s;
3758 
3759     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3760     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3761     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3762     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3763     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3764     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3765     ierr = PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");CHKERRQ(ierr);
3766   }
3767   *section = dm->defaultGlobalSection;
3768   PetscFunctionReturn(0);
3769 }
3770 
3771 /*@
3772   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3773 
3774   Input Parameters:
3775 + dm - The DM
3776 - section - The PetscSection, or NULL
3777 
3778   Level: intermediate
3779 
3780   Note: Any existing Section will be destroyed
3781 
3782 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3783 @*/
3784 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3785 {
3786   PetscErrorCode ierr;
3787 
3788   PetscFunctionBegin;
3789   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3790   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3791   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3792   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3793   dm->defaultGlobalSection = section;
3794 #if defined(PETSC_USE_DEBUG)
3795   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);CHKERRQ(ierr);}
3796 #endif
3797   PetscFunctionReturn(0);
3798 }
3799 
3800 /*@
3801   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3802   it is created from the default PetscSection layouts in the DM.
3803 
3804   Input Parameter:
3805 . dm - The DM
3806 
3807   Output Parameter:
3808 . sf - The PetscSF
3809 
3810   Level: intermediate
3811 
3812   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3813 
3814 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3815 @*/
3816 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3817 {
3818   PetscInt       nroots;
3819   PetscErrorCode ierr;
3820 
3821   PetscFunctionBegin;
3822   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3823   PetscValidPointer(sf, 2);
3824   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3825   if (nroots < 0) {
3826     PetscSection section, gSection;
3827 
3828     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3829     if (section) {
3830       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3831       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3832     } else {
3833       *sf = NULL;
3834       PetscFunctionReturn(0);
3835     }
3836   }
3837   *sf = dm->defaultSF;
3838   PetscFunctionReturn(0);
3839 }
3840 
3841 /*@
3842   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3843 
3844   Input Parameters:
3845 + dm - The DM
3846 - sf - The PetscSF
3847 
3848   Level: intermediate
3849 
3850   Note: Any previous SF is destroyed
3851 
3852 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3853 @*/
3854 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3855 {
3856   PetscErrorCode ierr;
3857 
3858   PetscFunctionBegin;
3859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3860   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3861   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3862   dm->defaultSF = sf;
3863   PetscFunctionReturn(0);
3864 }
3865 
3866 /*@C
3867   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3868   describing the data layout.
3869 
3870   Input Parameters:
3871 + dm - The DM
3872 . localSection - PetscSection describing the local data layout
3873 - globalSection - PetscSection describing the global data layout
3874 
3875   Level: intermediate
3876 
3877 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3878 @*/
3879 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3880 {
3881   MPI_Comm       comm;
3882   PetscLayout    layout;
3883   const PetscInt *ranges;
3884   PetscInt       *local;
3885   PetscSFNode    *remote;
3886   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3887   PetscMPIInt    size, rank;
3888   PetscErrorCode ierr;
3889 
3890   PetscFunctionBegin;
3891   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3893   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3894   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3895   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3896   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3897   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3898   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3899   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3900   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3901   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3902   for (p = pStart; p < pEnd; ++p) {
3903     PetscInt gdof, gcdof;
3904 
3905     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3906     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3907     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));
3908     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3909   }
3910   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3911   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3912   for (p = pStart, l = 0; p < pEnd; ++p) {
3913     const PetscInt *cind;
3914     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3915 
3916     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3917     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3918     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3919     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3920     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3921     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3922     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3923     if (!gdof) continue; /* Censored point */
3924     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3925     if (gsize != dof-cdof) {
3926       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);
3927       cdof = 0; /* Ignore constraints */
3928     }
3929     for (d = 0, c = 0; d < dof; ++d) {
3930       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3931       local[l+d-c] = off+d;
3932     }
3933     if (gdof < 0) {
3934       for (d = 0; d < gsize; ++d, ++l) {
3935         PetscInt offset = -(goff+1) + d, r;
3936 
3937         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3938         if (r < 0) r = -(r+2);
3939         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);
3940         remote[l].rank  = r;
3941         remote[l].index = offset - ranges[r];
3942       }
3943     } else {
3944       for (d = 0; d < gsize; ++d, ++l) {
3945         remote[l].rank  = rank;
3946         remote[l].index = goff+d - ranges[rank];
3947       }
3948     }
3949   }
3950   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3951   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3952   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3953   PetscFunctionReturn(0);
3954 }
3955 
3956 /*@
3957   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3958 
3959   Input Parameter:
3960 . dm - The DM
3961 
3962   Output Parameter:
3963 . sf - The PetscSF
3964 
3965   Level: intermediate
3966 
3967   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3968 
3969 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3970 @*/
3971 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3972 {
3973   PetscFunctionBegin;
3974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3975   PetscValidPointer(sf, 2);
3976   *sf = dm->sf;
3977   PetscFunctionReturn(0);
3978 }
3979 
3980 /*@
3981   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3982 
3983   Input Parameters:
3984 + dm - The DM
3985 - sf - The PetscSF
3986 
3987   Level: intermediate
3988 
3989 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3990 @*/
3991 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3992 {
3993   PetscErrorCode ierr;
3994 
3995   PetscFunctionBegin;
3996   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3997   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3998   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3999   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4000   dm->sf = sf;
4001   PetscFunctionReturn(0);
4002 }
4003 
4004 /*@
4005   DMGetDS - Get the PetscDS
4006 
4007   Input Parameter:
4008 . dm - The DM
4009 
4010   Output Parameter:
4011 . prob - The PetscDS
4012 
4013   Level: developer
4014 
4015 .seealso: DMSetDS()
4016 @*/
4017 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4018 {
4019   PetscFunctionBegin;
4020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4021   PetscValidPointer(prob, 2);
4022   *prob = dm->prob;
4023   PetscFunctionReturn(0);
4024 }
4025 
4026 /*@
4027   DMSetDS - Set the PetscDS
4028 
4029   Input Parameters:
4030 + dm - The DM
4031 - prob - The PetscDS
4032 
4033   Level: developer
4034 
4035 .seealso: DMGetDS()
4036 @*/
4037 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
4038 {
4039   PetscInt       dimEmbed;
4040   PetscErrorCode ierr;
4041 
4042   PetscFunctionBegin;
4043   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4044   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
4045   ierr = PetscObjectReference((PetscObject) prob);CHKERRQ(ierr);
4046   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
4047   dm->prob = prob;
4048   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
4049   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
4050   PetscFunctionReturn(0);
4051 }
4052 
4053 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4054 {
4055   PetscErrorCode ierr;
4056 
4057   PetscFunctionBegin;
4058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4059   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
4060   PetscFunctionReturn(0);
4061 }
4062 
4063 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4064 {
4065   PetscInt       Nf, f;
4066   PetscErrorCode ierr;
4067 
4068   PetscFunctionBegin;
4069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4070   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
4071   for (f = Nf; f < numFields; ++f) {
4072     PetscContainer obj;
4073 
4074     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4075     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
4076     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4077   }
4078   PetscFunctionReturn(0);
4079 }
4080 
4081 /*@
4082   DMGetField - Return the discretization object for a given DM field
4083 
4084   Not collective
4085 
4086   Input Parameters:
4087 + dm - The DM
4088 - f  - The field number
4089 
4090   Output Parameter:
4091 . field - The discretization object
4092 
4093   Level: developer
4094 
4095 .seealso: DMSetField()
4096 @*/
4097 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
4098 {
4099   PetscErrorCode ierr;
4100 
4101   PetscFunctionBegin;
4102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4103   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
4104   PetscFunctionReturn(0);
4105 }
4106 
4107 /*@
4108   DMSetField - Set the discretization object for a given DM field
4109 
4110   Logically collective on DM
4111 
4112   Input Parameters:
4113 + dm - The DM
4114 . f  - The field number
4115 - field - The discretization object
4116 
4117   Level: developer
4118 
4119 .seealso: DMGetField()
4120 @*/
4121 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
4122 {
4123   PetscErrorCode ierr;
4124 
4125   PetscFunctionBegin;
4126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4127   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
4128   PetscFunctionReturn(0);
4129 }
4130 
4131 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
4132 {
4133   DM dm_coord,dmc_coord;
4134   PetscErrorCode ierr;
4135   Vec coords,ccoords;
4136   Mat inject;
4137   PetscFunctionBegin;
4138   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
4139   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
4140   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
4141   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
4142   if (coords && !ccoords) {
4143     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
4144     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
4145     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
4146     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
4147     ierr = MatDestroy(&inject);CHKERRQ(ierr);
4148     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
4149     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
4150   }
4151   PetscFunctionReturn(0);
4152 }
4153 
4154 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
4155 {
4156   DM dm_coord,subdm_coord;
4157   PetscErrorCode ierr;
4158   Vec coords,ccoords,clcoords;
4159   VecScatter *scat_i,*scat_g;
4160   PetscFunctionBegin;
4161   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
4162   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
4163   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
4164   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
4165   if (coords && !ccoords) {
4166     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
4167     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
4168     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
4169     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
4170     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
4171     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4172     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4173     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4174     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4175     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
4176     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
4177     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
4178     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
4179     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
4180     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
4181     ierr = PetscFree(scat_i);CHKERRQ(ierr);
4182     ierr = PetscFree(scat_g);CHKERRQ(ierr);
4183   }
4184   PetscFunctionReturn(0);
4185 }
4186 
4187 /*@
4188   DMGetDimension - Return the topological dimension of the DM
4189 
4190   Not collective
4191 
4192   Input Parameter:
4193 . dm - The DM
4194 
4195   Output Parameter:
4196 . dim - The topological dimension
4197 
4198   Level: beginner
4199 
4200 .seealso: DMSetDimension(), DMCreate()
4201 @*/
4202 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
4203 {
4204   PetscFunctionBegin;
4205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4206   PetscValidPointer(dim, 2);
4207   *dim = dm->dim;
4208   PetscFunctionReturn(0);
4209 }
4210 
4211 /*@
4212   DMSetDimension - Set the topological dimension of the DM
4213 
4214   Collective on dm
4215 
4216   Input Parameters:
4217 + dm - The DM
4218 - dim - The topological dimension
4219 
4220   Level: beginner
4221 
4222 .seealso: DMGetDimension(), DMCreate()
4223 @*/
4224 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
4225 {
4226   PetscErrorCode ierr;
4227 
4228   PetscFunctionBegin;
4229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4230   PetscValidLogicalCollectiveInt(dm, dim, 2);
4231   dm->dim = dim;
4232   if (dm->prob->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dim);CHKERRQ(ierr);}
4233   PetscFunctionReturn(0);
4234 }
4235 
4236 /*@
4237   DMGetDimPoints - Get the half-open interval for all points of a given dimension
4238 
4239   Collective on DM
4240 
4241   Input Parameters:
4242 + dm - the DM
4243 - dim - the dimension
4244 
4245   Output Parameters:
4246 + pStart - The first point of the given dimension
4247 . pEnd - The first point following points of the given dimension
4248 
4249   Note:
4250   The points are vertices in the Hasse diagram encoding the topology. This is explained in
4251   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
4252   then the interval is empty.
4253 
4254   Level: intermediate
4255 
4256 .keywords: point, Hasse Diagram, dimension
4257 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
4258 @*/
4259 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4260 {
4261   PetscInt       d;
4262   PetscErrorCode ierr;
4263 
4264   PetscFunctionBegin;
4265   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4266   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
4267   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
4268   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
4269   PetscFunctionReturn(0);
4270 }
4271 
4272 /*@
4273   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
4274 
4275   Collective on DM
4276 
4277   Input Parameters:
4278 + dm - the DM
4279 - c - coordinate vector
4280 
4281   Note:
4282   The coordinates do include those for ghost points, which are in the local vector
4283 
4284   Level: intermediate
4285 
4286 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4287 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
4288 @*/
4289 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4290 {
4291   PetscErrorCode ierr;
4292 
4293   PetscFunctionBegin;
4294   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4295   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4296   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4297   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4298   dm->coordinates = c;
4299   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4300   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4301   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4302   PetscFunctionReturn(0);
4303 }
4304 
4305 /*@
4306   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
4307 
4308   Collective on DM
4309 
4310    Input Parameters:
4311 +  dm - the DM
4312 -  c - coordinate vector
4313 
4314   Note:
4315   The coordinates of ghost points can be set using DMSetCoordinates()
4316   followed by DMGetCoordinatesLocal(). This is intended to enable the
4317   setting of ghost coordinates outside of the domain.
4318 
4319   Level: intermediate
4320 
4321 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4322 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4323 @*/
4324 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4325 {
4326   PetscErrorCode ierr;
4327 
4328   PetscFunctionBegin;
4329   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4330   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4331   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4332   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4333 
4334   dm->coordinatesLocal = c;
4335 
4336   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4337   PetscFunctionReturn(0);
4338 }
4339 
4340 /*@
4341   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
4342 
4343   Not Collective
4344 
4345   Input Parameter:
4346 . dm - the DM
4347 
4348   Output Parameter:
4349 . c - global coordinate vector
4350 
4351   Note:
4352   This is a borrowed reference, so the user should NOT destroy this vector
4353 
4354   Each process has only the local coordinates (does NOT have the ghost coordinates).
4355 
4356   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4357   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4358 
4359   Level: intermediate
4360 
4361 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4362 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4363 @*/
4364 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4365 {
4366   PetscErrorCode ierr;
4367 
4368   PetscFunctionBegin;
4369   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4370   PetscValidPointer(c,2);
4371   if (!dm->coordinates && dm->coordinatesLocal) {
4372     DM cdm = NULL;
4373 
4374     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4375     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4376     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4377     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4378     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4379   }
4380   *c = dm->coordinates;
4381   PetscFunctionReturn(0);
4382 }
4383 
4384 /*@
4385   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4386 
4387   Collective on DM
4388 
4389   Input Parameter:
4390 . dm - the DM
4391 
4392   Output Parameter:
4393 . c - coordinate vector
4394 
4395   Note:
4396   This is a borrowed reference, so the user should NOT destroy this vector
4397 
4398   Each process has the local and ghost coordinates
4399 
4400   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4401   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4402 
4403   Level: intermediate
4404 
4405 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4406 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4407 @*/
4408 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4409 {
4410   PetscErrorCode ierr;
4411 
4412   PetscFunctionBegin;
4413   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4414   PetscValidPointer(c,2);
4415   if (!dm->coordinatesLocal && dm->coordinates) {
4416     DM cdm = NULL;
4417 
4418     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4419     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4420     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4421     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4422     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4423   }
4424   *c = dm->coordinatesLocal;
4425   PetscFunctionReturn(0);
4426 }
4427 
4428 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
4429 {
4430   PetscErrorCode ierr;
4431 
4432   PetscFunctionBegin;
4433   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4434   PetscValidPointer(field,2);
4435   if (!dm->coordinateField) {
4436     if (dm->ops->createcoordinatefield) {
4437       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
4438     }
4439   }
4440   *field = dm->coordinateField;
4441   PetscFunctionReturn(0);
4442 }
4443 
4444 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
4445 {
4446   PetscErrorCode ierr;
4447 
4448   PetscFunctionBegin;
4449   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4450   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
4451   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
4452   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
4453   dm->coordinateField = field;
4454   PetscFunctionReturn(0);
4455 }
4456 
4457 /*@
4458   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4459 
4460   Collective on DM
4461 
4462   Input Parameter:
4463 . dm - the DM
4464 
4465   Output Parameter:
4466 . cdm - coordinate DM
4467 
4468   Level: intermediate
4469 
4470 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4471 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4472 @*/
4473 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4474 {
4475   PetscErrorCode ierr;
4476 
4477   PetscFunctionBegin;
4478   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4479   PetscValidPointer(cdm,2);
4480   if (!dm->coordinateDM) {
4481     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4482     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4483   }
4484   *cdm = dm->coordinateDM;
4485   PetscFunctionReturn(0);
4486 }
4487 
4488 /*@
4489   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4490 
4491   Logically Collective on DM
4492 
4493   Input Parameters:
4494 + dm - the DM
4495 - cdm - coordinate DM
4496 
4497   Level: intermediate
4498 
4499 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4500 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4501 @*/
4502 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4503 {
4504   PetscErrorCode ierr;
4505 
4506   PetscFunctionBegin;
4507   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4508   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4509   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4510   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4511   dm->coordinateDM = cdm;
4512   PetscFunctionReturn(0);
4513 }
4514 
4515 /*@
4516   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4517 
4518   Not Collective
4519 
4520   Input Parameter:
4521 . dm - The DM object
4522 
4523   Output Parameter:
4524 . dim - The embedding dimension
4525 
4526   Level: intermediate
4527 
4528 .keywords: mesh, coordinates
4529 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4530 @*/
4531 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4532 {
4533   PetscFunctionBegin;
4534   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4535   PetscValidPointer(dim, 2);
4536   if (dm->dimEmbed == PETSC_DEFAULT) {
4537     dm->dimEmbed = dm->dim;
4538   }
4539   *dim = dm->dimEmbed;
4540   PetscFunctionReturn(0);
4541 }
4542 
4543 /*@
4544   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4545 
4546   Not Collective
4547 
4548   Input Parameters:
4549 + dm  - The DM object
4550 - dim - The embedding dimension
4551 
4552   Level: intermediate
4553 
4554 .keywords: mesh, coordinates
4555 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4556 @*/
4557 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4558 {
4559   PetscErrorCode ierr;
4560 
4561   PetscFunctionBegin;
4562   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4563   dm->dimEmbed = dim;
4564   ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);CHKERRQ(ierr);
4565   PetscFunctionReturn(0);
4566 }
4567 
4568 /*@
4569   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4570 
4571   Not Collective
4572 
4573   Input Parameter:
4574 . dm - The DM object
4575 
4576   Output Parameter:
4577 . section - The PetscSection object
4578 
4579   Level: intermediate
4580 
4581 .keywords: mesh, coordinates
4582 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4583 @*/
4584 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4585 {
4586   DM             cdm;
4587   PetscErrorCode ierr;
4588 
4589   PetscFunctionBegin;
4590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4591   PetscValidPointer(section, 2);
4592   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4593   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4594   PetscFunctionReturn(0);
4595 }
4596 
4597 /*@
4598   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4599 
4600   Not Collective
4601 
4602   Input Parameters:
4603 + dm      - The DM object
4604 . dim     - The embedding dimension, or PETSC_DETERMINE
4605 - section - The PetscSection object
4606 
4607   Level: intermediate
4608 
4609 .keywords: mesh, coordinates
4610 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4611 @*/
4612 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4613 {
4614   DM             cdm;
4615   PetscErrorCode ierr;
4616 
4617   PetscFunctionBegin;
4618   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4619   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4620   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4621   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4622   if (dim == PETSC_DETERMINE) {
4623     PetscInt d = PETSC_DEFAULT;
4624     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4625 
4626     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4627     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4628     pStart = PetscMax(vStart, pStart);
4629     pEnd   = PetscMin(vEnd, pEnd);
4630     for (v = pStart; v < pEnd; ++v) {
4631       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4632       if (dd) {d = dd; break;}
4633     }
4634     if (d < 0) d = PETSC_DEFAULT;
4635     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4636   }
4637   PetscFunctionReturn(0);
4638 }
4639 
4640 /*@C
4641   DMGetPeriodicity - Get the description of mesh periodicity
4642 
4643   Input Parameters:
4644 . dm      - The DM object
4645 
4646   Output Parameters:
4647 + per     - Whether the DM is periodic or not
4648 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4649 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4650 - bd      - This describes the type of periodicity in each topological dimension
4651 
4652   Level: developer
4653 
4654 .seealso: DMGetPeriodicity()
4655 @*/
4656 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4657 {
4658   PetscFunctionBegin;
4659   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4660   if (per)     *per     = dm->periodic;
4661   if (L)       *L       = dm->L;
4662   if (maxCell) *maxCell = dm->maxCell;
4663   if (bd)      *bd      = dm->bdtype;
4664   PetscFunctionReturn(0);
4665 }
4666 
4667 /*@C
4668   DMSetPeriodicity - Set the description of mesh periodicity
4669 
4670   Input Parameters:
4671 + dm      - The DM object
4672 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4673 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4674 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4675 - bd      - This describes the type of periodicity in each topological dimension
4676 
4677   Level: developer
4678 
4679 .seealso: DMGetPeriodicity()
4680 @*/
4681 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4682 {
4683   PetscInt       dim, d;
4684   PetscErrorCode ierr;
4685 
4686   PetscFunctionBegin;
4687   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4688   PetscValidLogicalCollectiveBool(dm,per,2);
4689   if (maxCell) {
4690     PetscValidPointer(maxCell,3);
4691     PetscValidPointer(L,4);
4692     PetscValidPointer(bd,5);
4693   }
4694   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4695   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4696   if (maxCell) {
4697     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4698     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4699     dm->periodic = PETSC_TRUE;
4700   } else {
4701     dm->periodic = per;
4702   }
4703   PetscFunctionReturn(0);
4704 }
4705 
4706 /*@
4707   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.
4708 
4709   Input Parameters:
4710 + dm     - The DM
4711 . in     - The input coordinate point (dim numbers)
4712 - endpoint - Include the endpoint L_i
4713 
4714   Output Parameter:
4715 . out - The localized coordinate point
4716 
4717   Level: developer
4718 
4719 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4720 @*/
4721 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4722 {
4723   PetscInt       dim, d;
4724   PetscErrorCode ierr;
4725 
4726   PetscFunctionBegin;
4727   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4728   if (!dm->maxCell) {
4729     for (d = 0; d < dim; ++d) out[d] = in[d];
4730   } else {
4731     if (endpoint) {
4732       for (d = 0; d < dim; ++d) {
4733         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)) {
4734           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4735         } else {
4736           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4737         }
4738       }
4739     } else {
4740       for (d = 0; d < dim; ++d) {
4741         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4742       }
4743     }
4744   }
4745   PetscFunctionReturn(0);
4746 }
4747 
4748 /*
4749   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.
4750 
4751   Input Parameters:
4752 + dm     - The DM
4753 . dim    - The spatial dimension
4754 . anchor - The anchor point, the input point can be no more than maxCell away from it
4755 - in     - The input coordinate point (dim numbers)
4756 
4757   Output Parameter:
4758 . out - The localized coordinate point
4759 
4760   Level: developer
4761 
4762   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
4763 
4764 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4765 */
4766 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4767 {
4768   PetscInt d;
4769 
4770   PetscFunctionBegin;
4771   if (!dm->maxCell) {
4772     for (d = 0; d < dim; ++d) out[d] = in[d];
4773   } else {
4774     for (d = 0; d < dim; ++d) {
4775       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4776         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4777       } else {
4778         out[d] = in[d];
4779       }
4780     }
4781   }
4782   PetscFunctionReturn(0);
4783 }
4784 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4785 {
4786   PetscInt d;
4787 
4788   PetscFunctionBegin;
4789   if (!dm->maxCell) {
4790     for (d = 0; d < dim; ++d) out[d] = in[d];
4791   } else {
4792     for (d = 0; d < dim; ++d) {
4793       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4794         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4795       } else {
4796         out[d] = in[d];
4797       }
4798     }
4799   }
4800   PetscFunctionReturn(0);
4801 }
4802 
4803 /*
4804   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.
4805 
4806   Input Parameters:
4807 + dm     - The DM
4808 . dim    - The spatial dimension
4809 . anchor - The anchor point, the input point can be no more than maxCell away from it
4810 . in     - The input coordinate delta (dim numbers)
4811 - out    - The input coordinate point (dim numbers)
4812 
4813   Output Parameter:
4814 . out    - The localized coordinate in + out
4815 
4816   Level: developer
4817 
4818   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
4819 
4820 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4821 */
4822 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4823 {
4824   PetscInt d;
4825 
4826   PetscFunctionBegin;
4827   if (!dm->maxCell) {
4828     for (d = 0; d < dim; ++d) out[d] += in[d];
4829   } else {
4830     for (d = 0; d < dim; ++d) {
4831       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4832         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4833       } else {
4834         out[d] += in[d];
4835       }
4836     }
4837   }
4838   PetscFunctionReturn(0);
4839 }
4840 
4841 /*@
4842   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4843 
4844   Input Parameter:
4845 . dm - The DM
4846 
4847   Output Parameter:
4848   areLocalized - True if localized
4849 
4850   Level: developer
4851 
4852 .seealso: DMLocalizeCoordinates()
4853 @*/
4854 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4855 {
4856   DM             cdm;
4857   PetscSection   coordSection;
4858   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
4859   PetscBool      isPlex, alreadyLocalized;
4860   PetscErrorCode ierr;
4861 
4862   PetscFunctionBegin;
4863   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4864   PetscValidPointer(areLocalized, 2);
4865 
4866   *areLocalized = PETSC_FALSE;
4867   if (!dm->periodic) PetscFunctionReturn(0); /* This is a hideous optimization hack! */
4868 
4869   /* We need some generic way of refering to cells/vertices */
4870   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4871   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4872   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
4873   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4874 
4875   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4876   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
4877   alreadyLocalized = PETSC_FALSE;
4878   for (c = cStart; c < cEnd; ++c) {
4879     if (c < sStart || c >= sEnd) continue;
4880     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4881     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
4882   }
4883   ierr = MPIU_Allreduce(&alreadyLocalized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4884   PetscFunctionReturn(0);
4885 }
4886 
4887 
4888 /*@
4889   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
4890 
4891   Input Parameter:
4892 . dm - The DM
4893 
4894   Level: developer
4895 
4896 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4897 @*/
4898 PetscErrorCode DMLocalizeCoordinates(DM dm)
4899 {
4900   DM             cdm;
4901   PetscSection   coordSection, cSection;
4902   Vec            coordinates,  cVec;
4903   PetscScalar   *coords, *coords2, *anchor, *localized;
4904   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4905   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4906   PetscInt       maxHeight = 0, h;
4907   PetscInt       *pStart = NULL, *pEnd = NULL;
4908   PetscErrorCode ierr;
4909 
4910   PetscFunctionBegin;
4911   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4912   if (!dm->periodic) PetscFunctionReturn(0);
4913   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
4914   if (alreadyLocalized) PetscFunctionReturn(0);
4915 
4916   /* We need some generic way of refering to cells/vertices */
4917   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4918   {
4919     PetscBool isplex;
4920 
4921     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4922     if (isplex) {
4923       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4924       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4925       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4926       pEnd = &pStart[maxHeight + 1];
4927       newStart = vStart;
4928       newEnd   = vEnd;
4929       for (h = 0; h <= maxHeight; h++) {
4930         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4931         newStart = PetscMin(newStart,pStart[h]);
4932         newEnd   = PetscMax(newEnd,pEnd[h]);
4933       }
4934     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4935   }
4936   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4937   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
4938   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4939   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4940   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4941 
4942   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4943   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4944   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4945   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4946   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4947 
4948   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4949   localized = &anchor[bs];
4950   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4951   for (h = 0; h <= maxHeight; h++) {
4952     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4953 
4954     for (c = cStart; c < cEnd; ++c) {
4955       PetscScalar *cellCoords = NULL;
4956       PetscInt     b;
4957 
4958       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4959       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4960       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4961       for (d = 0; d < dof/bs; ++d) {
4962         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
4963         for (b = 0; b < bs; b++) {
4964           if (cellCoords[d*bs + b] != localized[b]) break;
4965         }
4966         if (b < bs) break;
4967       }
4968       if (d < dof/bs) {
4969         if (c >= sStart && c < sEnd) {
4970           PetscInt cdof;
4971 
4972           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
4973           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4974         }
4975         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
4976         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
4977       }
4978       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4979     }
4980   }
4981   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4982   if (alreadyLocalizedGlobal) {
4983     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4984     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4985     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4986     PetscFunctionReturn(0);
4987   }
4988   for (v = vStart; v < vEnd; ++v) {
4989     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4990     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
4991     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
4992   }
4993   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
4994   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
4995   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
4996   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
4997   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
4998   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4999   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
5000   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5001   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
5002   for (v = vStart; v < vEnd; ++v) {
5003     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5004     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5005     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
5006     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
5007   }
5008   for (h = 0; h <= maxHeight; h++) {
5009     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5010 
5011     for (c = cStart; c < cEnd; ++c) {
5012       PetscScalar *cellCoords = NULL;
5013       PetscInt     b, cdof;
5014 
5015       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
5016       if (!cdof) continue;
5017       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5018       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
5019       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5020       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
5021       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5022     }
5023   }
5024   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5025   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5026   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5027   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
5028   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
5029   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
5030   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
5031   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5032   PetscFunctionReturn(0);
5033 }
5034 
5035 /*@
5036   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
5037 
5038   Collective on Vec v (see explanation below)
5039 
5040   Input Parameters:
5041 + dm - The DM
5042 . v - The Vec of points
5043 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
5044 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
5045 
5046   Output Parameter:
5047 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
5048 - cells - The PetscSF containing the ranks and local indices of the containing points.
5049 
5050 
5051   Level: developer
5052 
5053   Notes:
5054   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
5055   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
5056 
5057   If *cellSF is NULL on input, a PetscSF will be created.
5058   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
5059 
5060   An array that maps each point to its containing cell can be obtained with
5061 
5062 $    const PetscSFNode *cells;
5063 $    PetscInt           nFound;
5064 $    const PetscInt    *found;
5065 $
5066 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
5067 
5068   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
5069   the index of the cell in its rank's local numbering.
5070 
5071 .keywords: point location, mesh
5072 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
5073 @*/
5074 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
5075 {
5076   PetscErrorCode ierr;
5077 
5078   PetscFunctionBegin;
5079   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5080   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
5081   PetscValidPointer(cellSF,4);
5082   if (*cellSF) {
5083     PetscMPIInt result;
5084 
5085     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
5086     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
5087     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
5088   } else {
5089     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
5090   }
5091   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5092   if (dm->ops->locatepoints) {
5093     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
5094   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
5095   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5096   PetscFunctionReturn(0);
5097 }
5098 
5099 /*@
5100   DMGetOutputDM - Retrieve the DM associated with the layout for output
5101 
5102   Input Parameter:
5103 . dm - The original DM
5104 
5105   Output Parameter:
5106 . odm - The DM which provides the layout for output
5107 
5108   Level: intermediate
5109 
5110 .seealso: VecView(), DMGetDefaultGlobalSection()
5111 @*/
5112 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
5113 {
5114   PetscSection   section;
5115   PetscBool      hasConstraints, ghasConstraints;
5116   PetscErrorCode ierr;
5117 
5118   PetscFunctionBegin;
5119   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5120   PetscValidPointer(odm,2);
5121   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
5122   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
5123   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
5124   if (!ghasConstraints) {
5125     *odm = dm;
5126     PetscFunctionReturn(0);
5127   }
5128   if (!dm->dmBC) {
5129     PetscDS      ds;
5130     PetscSection newSection, gsection;
5131     PetscSF      sf;
5132 
5133     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
5134     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5135     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
5136     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
5137     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
5138     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
5139     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
5140     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
5141     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
5142     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
5143   }
5144   *odm = dm->dmBC;
5145   PetscFunctionReturn(0);
5146 }
5147 
5148 /*@
5149   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
5150 
5151   Input Parameter:
5152 . dm - The original DM
5153 
5154   Output Parameters:
5155 + num - The output sequence number
5156 - val - The output sequence value
5157 
5158   Level: intermediate
5159 
5160   Note: This is intended for output that should appear in sequence, for instance
5161   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5162 
5163 .seealso: VecView()
5164 @*/
5165 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
5166 {
5167   PetscFunctionBegin;
5168   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5169   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
5170   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
5171   PetscFunctionReturn(0);
5172 }
5173 
5174 /*@
5175   DMSetOutputSequenceNumber - Set the sequence number/value for output
5176 
5177   Input Parameters:
5178 + dm - The original DM
5179 . num - The output sequence number
5180 - val - The output sequence value
5181 
5182   Level: intermediate
5183 
5184   Note: This is intended for output that should appear in sequence, for instance
5185   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5186 
5187 .seealso: VecView()
5188 @*/
5189 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5190 {
5191   PetscFunctionBegin;
5192   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5193   dm->outputSequenceNum = num;
5194   dm->outputSequenceVal = val;
5195   PetscFunctionReturn(0);
5196 }
5197 
5198 /*@C
5199   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
5200 
5201   Input Parameters:
5202 + dm   - The original DM
5203 . name - The sequence name
5204 - num  - The output sequence number
5205 
5206   Output Parameter:
5207 . val  - The output sequence value
5208 
5209   Level: intermediate
5210 
5211   Note: This is intended for output that should appear in sequence, for instance
5212   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5213 
5214 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5215 @*/
5216 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5217 {
5218   PetscBool      ishdf5;
5219   PetscErrorCode ierr;
5220 
5221   PetscFunctionBegin;
5222   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5223   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
5224   PetscValidPointer(val,4);
5225   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
5226   if (ishdf5) {
5227 #if defined(PETSC_HAVE_HDF5)
5228     PetscScalar value;
5229 
5230     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
5231     *val = PetscRealPart(value);
5232 #endif
5233   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5234   PetscFunctionReturn(0);
5235 }
5236 
5237 /*@
5238   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
5239 
5240   Not collective
5241 
5242   Input Parameter:
5243 . dm - The DM
5244 
5245   Output Parameter:
5246 . useNatural - The flag to build the mapping to a natural order during distribution
5247 
5248   Level: beginner
5249 
5250 .seealso: DMSetUseNatural(), DMCreate()
5251 @*/
5252 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5253 {
5254   PetscFunctionBegin;
5255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5256   PetscValidPointer(useNatural, 2);
5257   *useNatural = dm->useNatural;
5258   PetscFunctionReturn(0);
5259 }
5260 
5261 /*@
5262   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
5263 
5264   Collective on dm
5265 
5266   Input Parameters:
5267 + dm - The DM
5268 - useNatural - The flag to build the mapping to a natural order during distribution
5269 
5270   Level: beginner
5271 
5272 .seealso: DMGetUseNatural(), DMCreate()
5273 @*/
5274 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5275 {
5276   PetscFunctionBegin;
5277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5278   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
5279   dm->useNatural = useNatural;
5280   PetscFunctionReturn(0);
5281 }
5282 
5283 
5284 /*@C
5285   DMCreateLabel - Create a label of the given name if it does not already exist
5286 
5287   Not Collective
5288 
5289   Input Parameters:
5290 + dm   - The DM object
5291 - name - The label name
5292 
5293   Level: intermediate
5294 
5295 .keywords: mesh
5296 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5297 @*/
5298 PetscErrorCode DMCreateLabel(DM dm, const char name[])
5299 {
5300   DMLabelLink    next  = dm->labels->next;
5301   PetscBool      flg   = PETSC_FALSE;
5302   PetscErrorCode ierr;
5303 
5304   PetscFunctionBegin;
5305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5306   PetscValidCharPointer(name, 2);
5307   while (next) {
5308     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5309     if (flg) break;
5310     next = next->next;
5311   }
5312   if (!flg) {
5313     DMLabelLink tmpLabel;
5314 
5315     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5316     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
5317     tmpLabel->output = PETSC_TRUE;
5318     tmpLabel->next   = dm->labels->next;
5319     dm->labels->next = tmpLabel;
5320   }
5321   PetscFunctionReturn(0);
5322 }
5323 
5324 /*@C
5325   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
5326 
5327   Not Collective
5328 
5329   Input Parameters:
5330 + dm   - The DM object
5331 . name - The label name
5332 - point - The mesh point
5333 
5334   Output Parameter:
5335 . value - The label value for this point, or -1 if the point is not in the label
5336 
5337   Level: beginner
5338 
5339 .keywords: mesh
5340 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5341 @*/
5342 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5343 {
5344   DMLabel        label;
5345   PetscErrorCode ierr;
5346 
5347   PetscFunctionBegin;
5348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5349   PetscValidCharPointer(name, 2);
5350   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5351   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5352   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
5353   PetscFunctionReturn(0);
5354 }
5355 
5356 /*@C
5357   DMSetLabelValue - Add a point to a Sieve Label with given value
5358 
5359   Not Collective
5360 
5361   Input Parameters:
5362 + dm   - The DM object
5363 . name - The label name
5364 . point - The mesh point
5365 - value - The label value for this point
5366 
5367   Output Parameter:
5368 
5369   Level: beginner
5370 
5371 .keywords: mesh
5372 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5373 @*/
5374 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5375 {
5376   DMLabel        label;
5377   PetscErrorCode ierr;
5378 
5379   PetscFunctionBegin;
5380   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5381   PetscValidCharPointer(name, 2);
5382   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5383   if (!label) {
5384     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
5385     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5386   }
5387   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
5388   PetscFunctionReturn(0);
5389 }
5390 
5391 /*@C
5392   DMClearLabelValue - Remove a point from a Sieve Label with given value
5393 
5394   Not Collective
5395 
5396   Input Parameters:
5397 + dm   - The DM object
5398 . name - The label name
5399 . point - The mesh point
5400 - value - The label value for this point
5401 
5402   Output Parameter:
5403 
5404   Level: beginner
5405 
5406 .keywords: mesh
5407 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5408 @*/
5409 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5410 {
5411   DMLabel        label;
5412   PetscErrorCode ierr;
5413 
5414   PetscFunctionBegin;
5415   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5416   PetscValidCharPointer(name, 2);
5417   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5418   if (!label) PetscFunctionReturn(0);
5419   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5420   PetscFunctionReturn(0);
5421 }
5422 
5423 /*@C
5424   DMGetLabelSize - Get the number of different integer ids in a Label
5425 
5426   Not Collective
5427 
5428   Input Parameters:
5429 + dm   - The DM object
5430 - name - The label name
5431 
5432   Output Parameter:
5433 . size - The number of different integer ids, or 0 if the label does not exist
5434 
5435   Level: beginner
5436 
5437 .keywords: mesh
5438 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5439 @*/
5440 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5441 {
5442   DMLabel        label;
5443   PetscErrorCode ierr;
5444 
5445   PetscFunctionBegin;
5446   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5447   PetscValidCharPointer(name, 2);
5448   PetscValidPointer(size, 3);
5449   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5450   *size = 0;
5451   if (!label) PetscFunctionReturn(0);
5452   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5453   PetscFunctionReturn(0);
5454 }
5455 
5456 /*@C
5457   DMGetLabelIdIS - Get the integer ids in a label
5458 
5459   Not Collective
5460 
5461   Input Parameters:
5462 + mesh - The DM object
5463 - name - The label name
5464 
5465   Output Parameter:
5466 . ids - The integer ids, or NULL if the label does not exist
5467 
5468   Level: beginner
5469 
5470 .keywords: mesh
5471 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5472 @*/
5473 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5474 {
5475   DMLabel        label;
5476   PetscErrorCode ierr;
5477 
5478   PetscFunctionBegin;
5479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5480   PetscValidCharPointer(name, 2);
5481   PetscValidPointer(ids, 3);
5482   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5483   *ids = NULL;
5484  if (label) {
5485     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5486   } else {
5487     /* returning an empty IS */
5488     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
5489   }
5490   PetscFunctionReturn(0);
5491 }
5492 
5493 /*@C
5494   DMGetStratumSize - Get the number of points in a label stratum
5495 
5496   Not Collective
5497 
5498   Input Parameters:
5499 + dm - The DM object
5500 . name - The label name
5501 - value - The stratum value
5502 
5503   Output Parameter:
5504 . size - The stratum size
5505 
5506   Level: beginner
5507 
5508 .keywords: mesh
5509 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5510 @*/
5511 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5512 {
5513   DMLabel        label;
5514   PetscErrorCode ierr;
5515 
5516   PetscFunctionBegin;
5517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5518   PetscValidCharPointer(name, 2);
5519   PetscValidPointer(size, 4);
5520   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5521   *size = 0;
5522   if (!label) PetscFunctionReturn(0);
5523   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5524   PetscFunctionReturn(0);
5525 }
5526 
5527 /*@C
5528   DMGetStratumIS - Get the points in a label stratum
5529 
5530   Not Collective
5531 
5532   Input Parameters:
5533 + dm - The DM object
5534 . name - The label name
5535 - value - The stratum value
5536 
5537   Output Parameter:
5538 . points - The stratum points, or NULL if the label does not exist or does not have that value
5539 
5540   Level: beginner
5541 
5542 .keywords: mesh
5543 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5544 @*/
5545 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5546 {
5547   DMLabel        label;
5548   PetscErrorCode ierr;
5549 
5550   PetscFunctionBegin;
5551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5552   PetscValidCharPointer(name, 2);
5553   PetscValidPointer(points, 4);
5554   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5555   *points = NULL;
5556   if (!label) PetscFunctionReturn(0);
5557   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5558   PetscFunctionReturn(0);
5559 }
5560 
5561 /*@C
5562   DMSetStratumIS - Set the points in a label stratum
5563 
5564   Not Collective
5565 
5566   Input Parameters:
5567 + dm - The DM object
5568 . name - The label name
5569 . value - The stratum value
5570 - points - The stratum points
5571 
5572   Level: beginner
5573 
5574 .keywords: mesh
5575 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5576 @*/
5577 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5578 {
5579   DMLabel        label;
5580   PetscErrorCode ierr;
5581 
5582   PetscFunctionBegin;
5583   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5584   PetscValidCharPointer(name, 2);
5585   PetscValidPointer(points, 4);
5586   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5587   if (!label) PetscFunctionReturn(0);
5588   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5589   PetscFunctionReturn(0);
5590 }
5591 
5592 /*@C
5593   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5594 
5595   Not Collective
5596 
5597   Input Parameters:
5598 + dm   - The DM object
5599 . name - The label name
5600 - value - The label value for this point
5601 
5602   Output Parameter:
5603 
5604   Level: beginner
5605 
5606 .keywords: mesh
5607 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5608 @*/
5609 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5610 {
5611   DMLabel        label;
5612   PetscErrorCode ierr;
5613 
5614   PetscFunctionBegin;
5615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5616   PetscValidCharPointer(name, 2);
5617   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5618   if (!label) PetscFunctionReturn(0);
5619   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5620   PetscFunctionReturn(0);
5621 }
5622 
5623 /*@
5624   DMGetNumLabels - Return the number of labels defined by the mesh
5625 
5626   Not Collective
5627 
5628   Input Parameter:
5629 . dm   - The DM object
5630 
5631   Output Parameter:
5632 . numLabels - the number of Labels
5633 
5634   Level: intermediate
5635 
5636 .keywords: mesh
5637 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5638 @*/
5639 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5640 {
5641   DMLabelLink next = dm->labels->next;
5642   PetscInt  n    = 0;
5643 
5644   PetscFunctionBegin;
5645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5646   PetscValidPointer(numLabels, 2);
5647   while (next) {++n; next = next->next;}
5648   *numLabels = n;
5649   PetscFunctionReturn(0);
5650 }
5651 
5652 /*@C
5653   DMGetLabelName - Return the name of nth label
5654 
5655   Not Collective
5656 
5657   Input Parameters:
5658 + dm - The DM object
5659 - n  - the label number
5660 
5661   Output Parameter:
5662 . name - the label name
5663 
5664   Level: intermediate
5665 
5666 .keywords: mesh
5667 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5668 @*/
5669 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5670 {
5671   DMLabelLink next = dm->labels->next;
5672   PetscInt  l    = 0;
5673 
5674   PetscFunctionBegin;
5675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5676   PetscValidPointer(name, 3);
5677   while (next) {
5678     if (l == n) {
5679       *name = next->label->name;
5680       PetscFunctionReturn(0);
5681     }
5682     ++l;
5683     next = next->next;
5684   }
5685   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5686 }
5687 
5688 /*@C
5689   DMHasLabel - Determine whether the mesh has a label of a given name
5690 
5691   Not Collective
5692 
5693   Input Parameters:
5694 + dm   - The DM object
5695 - name - The label name
5696 
5697   Output Parameter:
5698 . hasLabel - PETSC_TRUE if the label is present
5699 
5700   Level: intermediate
5701 
5702 .keywords: mesh
5703 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5704 @*/
5705 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5706 {
5707   DMLabelLink    next = dm->labels->next;
5708   PetscErrorCode ierr;
5709 
5710   PetscFunctionBegin;
5711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5712   PetscValidCharPointer(name, 2);
5713   PetscValidPointer(hasLabel, 3);
5714   *hasLabel = PETSC_FALSE;
5715   while (next) {
5716     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5717     if (*hasLabel) break;
5718     next = next->next;
5719   }
5720   PetscFunctionReturn(0);
5721 }
5722 
5723 /*@C
5724   DMGetLabel - Return the label of a given name, or NULL
5725 
5726   Not Collective
5727 
5728   Input Parameters:
5729 + dm   - The DM object
5730 - name - The label name
5731 
5732   Output Parameter:
5733 . label - The DMLabel, or NULL if the label is absent
5734 
5735   Level: intermediate
5736 
5737 .keywords: mesh
5738 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5739 @*/
5740 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5741 {
5742   DMLabelLink    next = dm->labels->next;
5743   PetscBool      hasLabel;
5744   PetscErrorCode ierr;
5745 
5746   PetscFunctionBegin;
5747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5748   PetscValidCharPointer(name, 2);
5749   PetscValidPointer(label, 3);
5750   *label = NULL;
5751   while (next) {
5752     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5753     if (hasLabel) {
5754       *label = next->label;
5755       break;
5756     }
5757     next = next->next;
5758   }
5759   PetscFunctionReturn(0);
5760 }
5761 
5762 /*@C
5763   DMGetLabelByNum - Return the nth label
5764 
5765   Not Collective
5766 
5767   Input Parameters:
5768 + dm - The DM object
5769 - n  - the label number
5770 
5771   Output Parameter:
5772 . label - the label
5773 
5774   Level: intermediate
5775 
5776 .keywords: mesh
5777 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5778 @*/
5779 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5780 {
5781   DMLabelLink next = dm->labels->next;
5782   PetscInt    l    = 0;
5783 
5784   PetscFunctionBegin;
5785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5786   PetscValidPointer(label, 3);
5787   while (next) {
5788     if (l == n) {
5789       *label = next->label;
5790       PetscFunctionReturn(0);
5791     }
5792     ++l;
5793     next = next->next;
5794   }
5795   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5796 }
5797 
5798 /*@C
5799   DMAddLabel - Add the label to this mesh
5800 
5801   Not Collective
5802 
5803   Input Parameters:
5804 + dm   - The DM object
5805 - label - The DMLabel
5806 
5807   Level: developer
5808 
5809 .keywords: mesh
5810 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5811 @*/
5812 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5813 {
5814   DMLabelLink    tmpLabel;
5815   PetscBool      hasLabel;
5816   PetscErrorCode ierr;
5817 
5818   PetscFunctionBegin;
5819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5820   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5821   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5822   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5823   tmpLabel->label  = label;
5824   tmpLabel->output = PETSC_TRUE;
5825   tmpLabel->next   = dm->labels->next;
5826   dm->labels->next = tmpLabel;
5827   PetscFunctionReturn(0);
5828 }
5829 
5830 /*@C
5831   DMRemoveLabel - Remove the label from this mesh
5832 
5833   Not Collective
5834 
5835   Input Parameters:
5836 + dm   - The DM object
5837 - name - The label name
5838 
5839   Output Parameter:
5840 . label - The DMLabel, or NULL if the label is absent
5841 
5842   Level: developer
5843 
5844 .keywords: mesh
5845 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5846 @*/
5847 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5848 {
5849   DMLabelLink    next = dm->labels->next;
5850   DMLabelLink    last = NULL;
5851   PetscBool      hasLabel;
5852   PetscErrorCode ierr;
5853 
5854   PetscFunctionBegin;
5855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5856   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5857   *label = NULL;
5858   if (!hasLabel) PetscFunctionReturn(0);
5859   while (next) {
5860     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5861     if (hasLabel) {
5862       if (last) last->next       = next->next;
5863       else      dm->labels->next = next->next;
5864       next->next = NULL;
5865       *label     = next->label;
5866       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5867       if (hasLabel) {
5868         dm->depthLabel = NULL;
5869       }
5870       ierr = PetscFree(next);CHKERRQ(ierr);
5871       break;
5872     }
5873     last = next;
5874     next = next->next;
5875   }
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 /*@C
5880   DMGetLabelOutput - Get the output flag for a given label
5881 
5882   Not Collective
5883 
5884   Input Parameters:
5885 + dm   - The DM object
5886 - name - The label name
5887 
5888   Output Parameter:
5889 . output - The flag for output
5890 
5891   Level: developer
5892 
5893 .keywords: mesh
5894 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5895 @*/
5896 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5897 {
5898   DMLabelLink    next = dm->labels->next;
5899   PetscErrorCode ierr;
5900 
5901   PetscFunctionBegin;
5902   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5903   PetscValidPointer(name, 2);
5904   PetscValidPointer(output, 3);
5905   while (next) {
5906     PetscBool flg;
5907 
5908     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5909     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5910     next = next->next;
5911   }
5912   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5913 }
5914 
5915 /*@C
5916   DMSetLabelOutput - Set the output flag for a given label
5917 
5918   Not Collective
5919 
5920   Input Parameters:
5921 + dm     - The DM object
5922 . name   - The label name
5923 - output - The flag for output
5924 
5925   Level: developer
5926 
5927 .keywords: mesh
5928 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5929 @*/
5930 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5931 {
5932   DMLabelLink    next = dm->labels->next;
5933   PetscErrorCode ierr;
5934 
5935   PetscFunctionBegin;
5936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5937   PetscValidPointer(name, 2);
5938   while (next) {
5939     PetscBool flg;
5940 
5941     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5942     if (flg) {next->output = output; PetscFunctionReturn(0);}
5943     next = next->next;
5944   }
5945   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5946 }
5947 
5948 
5949 /*@
5950   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5951 
5952   Collective on DM
5953 
5954   Input Parameter:
5955 . dmA - The DM object with initial labels
5956 
5957   Output Parameter:
5958 . dmB - The DM object with copied labels
5959 
5960   Level: intermediate
5961 
5962   Note: This is typically used when interpolating or otherwise adding to a mesh
5963 
5964 .keywords: mesh
5965 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5966 @*/
5967 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5968 {
5969   PetscInt       numLabels, l;
5970   PetscErrorCode ierr;
5971 
5972   PetscFunctionBegin;
5973   if (dmA == dmB) PetscFunctionReturn(0);
5974   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5975   for (l = 0; l < numLabels; ++l) {
5976     DMLabel     label, labelNew;
5977     const char *name;
5978     PetscBool   flg;
5979 
5980     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5981     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5982     if (flg) continue;
5983     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
5984     if (flg) continue;
5985     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5986     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5987     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5988   }
5989   PetscFunctionReturn(0);
5990 }
5991 
5992 /*@
5993   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5994 
5995   Input Parameter:
5996 . dm - The DM object
5997 
5998   Output Parameter:
5999 . cdm - The coarse DM
6000 
6001   Level: intermediate
6002 
6003 .seealso: DMSetCoarseDM()
6004 @*/
6005 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
6006 {
6007   PetscFunctionBegin;
6008   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6009   PetscValidPointer(cdm, 2);
6010   *cdm = dm->coarseMesh;
6011   PetscFunctionReturn(0);
6012 }
6013 
6014 /*@
6015   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
6016 
6017   Input Parameters:
6018 + dm - The DM object
6019 - cdm - The coarse DM
6020 
6021   Level: intermediate
6022 
6023 .seealso: DMGetCoarseDM()
6024 @*/
6025 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
6026 {
6027   PetscErrorCode ierr;
6028 
6029   PetscFunctionBegin;
6030   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6031   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
6032   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6033   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
6034   dm->coarseMesh = cdm;
6035   PetscFunctionReturn(0);
6036 }
6037 
6038 /*@
6039   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
6040 
6041   Input Parameter:
6042 . dm - The DM object
6043 
6044   Output Parameter:
6045 . fdm - The fine DM
6046 
6047   Level: intermediate
6048 
6049 .seealso: DMSetFineDM()
6050 @*/
6051 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
6052 {
6053   PetscFunctionBegin;
6054   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6055   PetscValidPointer(fdm, 2);
6056   *fdm = dm->fineMesh;
6057   PetscFunctionReturn(0);
6058 }
6059 
6060 /*@
6061   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
6062 
6063   Input Parameters:
6064 + dm - The DM object
6065 - fdm - The fine DM
6066 
6067   Level: intermediate
6068 
6069 .seealso: DMGetFineDM()
6070 @*/
6071 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
6072 {
6073   PetscErrorCode ierr;
6074 
6075   PetscFunctionBegin;
6076   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6077   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
6078   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
6079   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
6080   dm->fineMesh = fdm;
6081   PetscFunctionReturn(0);
6082 }
6083 
6084 /*=== DMBoundary code ===*/
6085 
6086 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
6087 {
6088   PetscErrorCode ierr;
6089 
6090   PetscFunctionBegin;
6091   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
6092   PetscFunctionReturn(0);
6093 }
6094 
6095 /*@C
6096   DMAddBoundary - Add a boundary condition to the model
6097 
6098   Input Parameters:
6099 + dm          - The DM, with a PetscDS that matches the problem being constrained
6100 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6101 . name        - The BC name
6102 . labelname   - The label defining constrained points
6103 . field       - The field to constrain
6104 . numcomps    - The number of constrained field components
6105 . comps       - An array of constrained component numbers
6106 . bcFunc      - A pointwise function giving boundary values
6107 . numids      - The number of DMLabel ids for constrained points
6108 . ids         - An array of ids for constrained points
6109 - ctx         - An optional user context for bcFunc
6110 
6111   Options Database Keys:
6112 + -bc_<boundary name> <num> - Overrides the boundary ids
6113 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6114 
6115   Level: developer
6116 
6117 .seealso: DMGetBoundary()
6118 @*/
6119 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
6120 {
6121   PetscErrorCode ierr;
6122 
6123   PetscFunctionBegin;
6124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6125   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
6126   PetscFunctionReturn(0);
6127 }
6128 
6129 /*@
6130   DMGetNumBoundary - Get the number of registered BC
6131 
6132   Input Parameters:
6133 . dm - The mesh object
6134 
6135   Output Parameters:
6136 . numBd - The number of BC
6137 
6138   Level: intermediate
6139 
6140 .seealso: DMAddBoundary(), DMGetBoundary()
6141 @*/
6142 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
6143 {
6144   PetscErrorCode ierr;
6145 
6146   PetscFunctionBegin;
6147   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6148   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
6149   PetscFunctionReturn(0);
6150 }
6151 
6152 /*@C
6153   DMGetBoundary - Get a model boundary condition
6154 
6155   Input Parameters:
6156 + dm          - The mesh object
6157 - bd          - The BC number
6158 
6159   Output Parameters:
6160 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6161 . name        - The BC name
6162 . labelname   - The label defining constrained points
6163 . field       - The field to constrain
6164 . numcomps    - The number of constrained field components
6165 . comps       - An array of constrained component numbers
6166 . bcFunc      - A pointwise function giving boundary values
6167 . numids      - The number of DMLabel ids for constrained points
6168 . ids         - An array of ids for constrained points
6169 - ctx         - An optional user context for bcFunc
6170 
6171   Options Database Keys:
6172 + -bc_<boundary name> <num> - Overrides the boundary ids
6173 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6174 
6175   Level: developer
6176 
6177 .seealso: DMAddBoundary()
6178 @*/
6179 PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
6180 {
6181   PetscErrorCode ierr;
6182 
6183   PetscFunctionBegin;
6184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6185   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
6186   PetscFunctionReturn(0);
6187 }
6188 
6189 static PetscErrorCode DMPopulateBoundary(DM dm)
6190 {
6191   DMBoundary *lastnext;
6192   DSBoundary dsbound;
6193   PetscErrorCode ierr;
6194 
6195   PetscFunctionBegin;
6196   dsbound = dm->prob->boundary;
6197   if (dm->boundary) {
6198     DMBoundary next = dm->boundary;
6199 
6200     /* quick check to see if the PetscDS has changed */
6201     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
6202     /* the PetscDS has changed: tear down and rebuild */
6203     while (next) {
6204       DMBoundary b = next;
6205 
6206       next = b->next;
6207       ierr = PetscFree(b);CHKERRQ(ierr);
6208     }
6209     dm->boundary = NULL;
6210   }
6211 
6212   lastnext = &(dm->boundary);
6213   while (dsbound) {
6214     DMBoundary dmbound;
6215 
6216     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
6217     dmbound->dsboundary = dsbound;
6218     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
6219     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
6220     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6221     *lastnext = dmbound;
6222     lastnext = &(dmbound->next);
6223     dsbound = dsbound->next;
6224   }
6225   PetscFunctionReturn(0);
6226 }
6227 
6228 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6229 {
6230   DMBoundary     b;
6231   PetscErrorCode ierr;
6232 
6233   PetscFunctionBegin;
6234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6235   PetscValidPointer(isBd, 3);
6236   *isBd = PETSC_FALSE;
6237   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
6238   b = dm->boundary;
6239   while (b && !(*isBd)) {
6240     DMLabel    label = b->label;
6241     DSBoundary dsb = b->dsboundary;
6242 
6243     if (label) {
6244       PetscInt i;
6245 
6246       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6247         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
6248       }
6249     }
6250     b = b->next;
6251   }
6252   PetscFunctionReturn(0);
6253 }
6254 
6255 /*@C
6256   DMProjectFunction - This projects the given function into the function space provided.
6257 
6258   Input Parameters:
6259 + dm      - The DM
6260 . time    - The time
6261 . funcs   - The coordinate functions to evaluate, one per field
6262 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6263 - mode    - The insertion mode for values
6264 
6265   Output Parameter:
6266 . X - vector
6267 
6268    Calling sequence of func:
6269 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
6270 
6271 +  dim - The spatial dimension
6272 .  x   - The coordinates
6273 .  Nf  - The number of fields
6274 .  u   - The output field values
6275 -  ctx - optional user-defined function context
6276 
6277   Level: developer
6278 
6279 .seealso: DMComputeL2Diff()
6280 @*/
6281 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6282 {
6283   Vec            localX;
6284   PetscErrorCode ierr;
6285 
6286   PetscFunctionBegin;
6287   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6288   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6289   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6290   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6291   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6292   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6293   PetscFunctionReturn(0);
6294 }
6295 
6296 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6297 {
6298   PetscErrorCode ierr;
6299 
6300   PetscFunctionBegin;
6301   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6302   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6303   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6304   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6305   PetscFunctionReturn(0);
6306 }
6307 
6308 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)
6309 {
6310   Vec            localX;
6311   PetscErrorCode ierr;
6312 
6313   PetscFunctionBegin;
6314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6315   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6316   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6317   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6318   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6319   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6320   PetscFunctionReturn(0);
6321 }
6322 
6323 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)
6324 {
6325   PetscErrorCode ierr;
6326 
6327   PetscFunctionBegin;
6328   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6329   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6330   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6331   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6332   PetscFunctionReturn(0);
6333 }
6334 
6335 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6336                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6337                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6338                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6339                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6340                                    InsertMode mode, Vec localX)
6341 {
6342   PetscErrorCode ierr;
6343 
6344   PetscFunctionBegin;
6345   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6346   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
6347   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
6348   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6349   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
6350   PetscFunctionReturn(0);
6351 }
6352 
6353 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6354                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6355                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6356                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6357                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6358                                         InsertMode mode, Vec localX)
6359 {
6360   PetscErrorCode ierr;
6361 
6362   PetscFunctionBegin;
6363   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6364   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
6365   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
6366   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6367   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
6368   PetscFunctionReturn(0);
6369 }
6370 
6371 /*@C
6372   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
6373 
6374   Input Parameters:
6375 + dm    - The DM
6376 . time  - The time
6377 . funcs - The functions to evaluate for each field component
6378 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6379 - X     - The coefficient vector u_h, a global vector
6380 
6381   Output Parameter:
6382 . diff - The diff ||u - u_h||_2
6383 
6384   Level: developer
6385 
6386 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6387 @*/
6388 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6389 {
6390   PetscErrorCode ierr;
6391 
6392   PetscFunctionBegin;
6393   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6394   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6395   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6396   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6397   PetscFunctionReturn(0);
6398 }
6399 
6400 /*@C
6401   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
6402 
6403   Input Parameters:
6404 + dm    - The DM
6405 , time  - The time
6406 . funcs - The gradient functions to evaluate for each field component
6407 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6408 . X     - The coefficient vector u_h, a global vector
6409 - n     - The vector to project along
6410 
6411   Output Parameter:
6412 . diff - The diff ||(grad u - grad u_h) . n||_2
6413 
6414   Level: developer
6415 
6416 .seealso: DMProjectFunction(), DMComputeL2Diff()
6417 @*/
6418 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)
6419 {
6420   PetscErrorCode ierr;
6421 
6422   PetscFunctionBegin;
6423   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6424   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6425   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6426   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6427   PetscFunctionReturn(0);
6428 }
6429 
6430 /*@C
6431   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6432 
6433   Input Parameters:
6434 + dm    - The DM
6435 . time  - The time
6436 . funcs - The functions to evaluate for each field component
6437 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6438 - X     - The coefficient vector u_h, a global vector
6439 
6440   Output Parameter:
6441 . diff - The array of differences, ||u^f - u^f_h||_2
6442 
6443   Level: developer
6444 
6445 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6446 @*/
6447 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6448 {
6449   PetscErrorCode ierr;
6450 
6451   PetscFunctionBegin;
6452   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6453   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6454   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6455   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6456   PetscFunctionReturn(0);
6457 }
6458 
6459 /*@C
6460   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6461                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6462 
6463   Collective on dm
6464 
6465   Input parameters:
6466 + dm - the pre-adaptation DM object
6467 - label - label with the flags
6468 
6469   Output parameters:
6470 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
6471 
6472   Level: intermediate
6473 
6474 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6475 @*/
6476 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6477 {
6478   PetscErrorCode ierr;
6479 
6480   PetscFunctionBegin;
6481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6482   PetscValidPointer(label,2);
6483   PetscValidPointer(dmAdapt,3);
6484   *dmAdapt = NULL;
6485   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6486   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
6487   PetscFunctionReturn(0);
6488 }
6489 
6490 /*@C
6491   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
6492 
6493   Input Parameters:
6494 + dm - The DM object
6495 . metric - The metric to which the mesh is adapted, defined vertex-wise.
6496 - 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_".
6497 
6498   Output Parameter:
6499 . dmAdapt  - Pointer to the DM object containing the adapted mesh
6500 
6501   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
6502 
6503   Level: advanced
6504 
6505 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6506 @*/
6507 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6508 {
6509   PetscErrorCode ierr;
6510 
6511   PetscFunctionBegin;
6512   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6513   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
6514   if (bdLabel) PetscValidPointer(bdLabel, 3);
6515   PetscValidPointer(dmAdapt, 4);
6516   *dmAdapt = NULL;
6517   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6518   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
6519   PetscFunctionReturn(0);
6520 }
6521 
6522 /*@C
6523  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6524 
6525  Not Collective
6526 
6527  Input Parameter:
6528  . dm    - The DM
6529 
6530  Output Parameter:
6531  . nranks - the number of neighbours
6532  . ranks - the neighbors ranks
6533 
6534  Notes:
6535  Do not free the array, it is freed when the DM is destroyed.
6536 
6537  Level: beginner
6538 
6539  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6540 @*/
6541 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6542 {
6543   PetscErrorCode ierr;
6544 
6545   PetscFunctionBegin;
6546   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6547   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6548   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6549   PetscFunctionReturn(0);
6550 }
6551 
6552 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6553 
6554 /*
6555     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6556     This has be a different function because it requires DM which is not defined in the Mat library
6557 */
6558 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6559 {
6560   PetscErrorCode ierr;
6561 
6562   PetscFunctionBegin;
6563   if (coloring->ctype == IS_COLORING_LOCAL) {
6564     Vec x1local;
6565     DM  dm;
6566     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6567     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6568     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6569     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6570     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6571     x1   = x1local;
6572   }
6573   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6574   if (coloring->ctype == IS_COLORING_LOCAL) {
6575     DM  dm;
6576     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6577     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6578   }
6579   PetscFunctionReturn(0);
6580 }
6581 
6582 /*@
6583     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6584 
6585     Input Parameter:
6586 .    coloring - the MatFDColoring object
6587 
6588     Developer Notes:
6589     this routine exists because the PETSc Mat library does not know about the DM objects
6590 
6591     Level: advanced
6592 
6593 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6594 @*/
6595 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6596 {
6597   PetscFunctionBegin;
6598   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6599   PetscFunctionReturn(0);
6600 }
6601