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