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