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