xref: /petsc/src/dm/interface/dm.c (revision a8f87f1dd689f82917d46bbc2fdc0da7b40626d1)
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   Notes:
4283   The coordinates do include those for ghost points, which are in the local vector.
4284 
4285   The vector c should be destroyed by the caller.
4286 
4287   Level: intermediate
4288 
4289 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4290 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4291 @*/
4292 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4293 {
4294   PetscErrorCode ierr;
4295 
4296   PetscFunctionBegin;
4297   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4298   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4299   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4300   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4301   dm->coordinates = c;
4302   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4303   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4304   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4305   PetscFunctionReturn(0);
4306 }
4307 
4308 /*@
4309   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
4310 
4311   Collective on DM
4312 
4313    Input Parameters:
4314 +  dm - the DM
4315 -  c - coordinate vector
4316 
4317   Notes:
4318   The coordinates of ghost points can be set using DMSetCoordinates()
4319   followed by DMGetCoordinatesLocal(). This is intended to enable the
4320   setting of ghost coordinates outside of the domain.
4321 
4322   The vector c should be destroyed by the caller.
4323 
4324   Level: intermediate
4325 
4326 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4327 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4328 @*/
4329 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4330 {
4331   PetscErrorCode ierr;
4332 
4333   PetscFunctionBegin;
4334   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4335   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4336   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4337   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4338 
4339   dm->coordinatesLocal = c;
4340 
4341   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4342   PetscFunctionReturn(0);
4343 }
4344 
4345 /*@
4346   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
4347 
4348   Not Collective
4349 
4350   Input Parameter:
4351 . dm - the DM
4352 
4353   Output Parameter:
4354 . c - global coordinate vector
4355 
4356   Note:
4357   This is a borrowed reference, so the user should NOT destroy this vector
4358 
4359   Each process has only the local coordinates (does NOT have the ghost coordinates).
4360 
4361   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4362   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4363 
4364   Level: intermediate
4365 
4366 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4367 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4368 @*/
4369 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4370 {
4371   PetscErrorCode ierr;
4372 
4373   PetscFunctionBegin;
4374   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4375   PetscValidPointer(c,2);
4376   if (!dm->coordinates && dm->coordinatesLocal) {
4377     DM cdm = NULL;
4378 
4379     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4380     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4381     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4382     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4383     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4384   }
4385   *c = dm->coordinates;
4386   PetscFunctionReturn(0);
4387 }
4388 
4389 /*@
4390   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4391 
4392   Collective on DM
4393 
4394   Input Parameter:
4395 . dm - the DM
4396 
4397   Output Parameter:
4398 . c - coordinate vector
4399 
4400   Note:
4401   This is a borrowed reference, so the user should NOT destroy this vector
4402 
4403   Each process has the local and ghost coordinates
4404 
4405   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4406   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4407 
4408   Level: intermediate
4409 
4410 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4411 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4412 @*/
4413 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4414 {
4415   PetscErrorCode ierr;
4416 
4417   PetscFunctionBegin;
4418   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4419   PetscValidPointer(c,2);
4420   if (!dm->coordinatesLocal && dm->coordinates) {
4421     DM cdm = NULL;
4422 
4423     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4424     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4425     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4426     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4427     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4428   }
4429   *c = dm->coordinatesLocal;
4430   PetscFunctionReturn(0);
4431 }
4432 
4433 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
4434 {
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4439   PetscValidPointer(field,2);
4440   if (!dm->coordinateField) {
4441     if (dm->ops->createcoordinatefield) {
4442       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
4443     }
4444   }
4445   *field = dm->coordinateField;
4446   PetscFunctionReturn(0);
4447 }
4448 
4449 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
4450 {
4451   PetscErrorCode ierr;
4452 
4453   PetscFunctionBegin;
4454   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4455   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
4456   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
4457   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
4458   dm->coordinateField = field;
4459   PetscFunctionReturn(0);
4460 }
4461 
4462 /*@
4463   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4464 
4465   Collective on DM
4466 
4467   Input Parameter:
4468 . dm - the DM
4469 
4470   Output Parameter:
4471 . cdm - coordinate DM
4472 
4473   Level: intermediate
4474 
4475 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4476 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4477 @*/
4478 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4479 {
4480   PetscErrorCode ierr;
4481 
4482   PetscFunctionBegin;
4483   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4484   PetscValidPointer(cdm,2);
4485   if (!dm->coordinateDM) {
4486     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4487     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4488   }
4489   *cdm = dm->coordinateDM;
4490   PetscFunctionReturn(0);
4491 }
4492 
4493 /*@
4494   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4495 
4496   Logically Collective on DM
4497 
4498   Input Parameters:
4499 + dm - the DM
4500 - cdm - coordinate DM
4501 
4502   Level: intermediate
4503 
4504 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4505 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4506 @*/
4507 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4508 {
4509   PetscErrorCode ierr;
4510 
4511   PetscFunctionBegin;
4512   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4513   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4514   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4515   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4516   dm->coordinateDM = cdm;
4517   PetscFunctionReturn(0);
4518 }
4519 
4520 /*@
4521   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4522 
4523   Not Collective
4524 
4525   Input Parameter:
4526 . dm - The DM object
4527 
4528   Output Parameter:
4529 . dim - The embedding dimension
4530 
4531   Level: intermediate
4532 
4533 .keywords: mesh, coordinates
4534 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4535 @*/
4536 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4537 {
4538   PetscFunctionBegin;
4539   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4540   PetscValidPointer(dim, 2);
4541   if (dm->dimEmbed == PETSC_DEFAULT) {
4542     dm->dimEmbed = dm->dim;
4543   }
4544   *dim = dm->dimEmbed;
4545   PetscFunctionReturn(0);
4546 }
4547 
4548 /*@
4549   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4550 
4551   Not Collective
4552 
4553   Input Parameters:
4554 + dm  - The DM object
4555 - dim - The embedding dimension
4556 
4557   Level: intermediate
4558 
4559 .keywords: mesh, coordinates
4560 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4561 @*/
4562 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4563 {
4564   PetscErrorCode ierr;
4565 
4566   PetscFunctionBegin;
4567   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4568   dm->dimEmbed = dim;
4569   ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);CHKERRQ(ierr);
4570   PetscFunctionReturn(0);
4571 }
4572 
4573 /*@
4574   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4575 
4576   Not Collective
4577 
4578   Input Parameter:
4579 . dm - The DM object
4580 
4581   Output Parameter:
4582 . section - The PetscSection object
4583 
4584   Level: intermediate
4585 
4586 .keywords: mesh, coordinates
4587 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4588 @*/
4589 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4590 {
4591   DM             cdm;
4592   PetscErrorCode ierr;
4593 
4594   PetscFunctionBegin;
4595   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4596   PetscValidPointer(section, 2);
4597   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4598   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4599   PetscFunctionReturn(0);
4600 }
4601 
4602 /*@
4603   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4604 
4605   Not Collective
4606 
4607   Input Parameters:
4608 + dm      - The DM object
4609 . dim     - The embedding dimension, or PETSC_DETERMINE
4610 - section - The PetscSection object
4611 
4612   Level: intermediate
4613 
4614 .keywords: mesh, coordinates
4615 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4616 @*/
4617 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4618 {
4619   DM             cdm;
4620   PetscErrorCode ierr;
4621 
4622   PetscFunctionBegin;
4623   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4624   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4625   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4626   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4627   if (dim == PETSC_DETERMINE) {
4628     PetscInt d = PETSC_DEFAULT;
4629     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4630 
4631     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4632     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4633     pStart = PetscMax(vStart, pStart);
4634     pEnd   = PetscMin(vEnd, pEnd);
4635     for (v = pStart; v < pEnd; ++v) {
4636       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4637       if (dd) {d = dd; break;}
4638     }
4639     if (d < 0) d = PETSC_DEFAULT;
4640     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4641   }
4642   PetscFunctionReturn(0);
4643 }
4644 
4645 /*@C
4646   DMGetPeriodicity - Get the description of mesh periodicity
4647 
4648   Input Parameters:
4649 . dm      - The DM object
4650 
4651   Output Parameters:
4652 + per     - Whether the DM is periodic or not
4653 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4654 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4655 - bd      - This describes the type of periodicity in each topological dimension
4656 
4657   Level: developer
4658 
4659 .seealso: DMGetPeriodicity()
4660 @*/
4661 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4662 {
4663   PetscFunctionBegin;
4664   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4665   if (per)     *per     = dm->periodic;
4666   if (L)       *L       = dm->L;
4667   if (maxCell) *maxCell = dm->maxCell;
4668   if (bd)      *bd      = dm->bdtype;
4669   PetscFunctionReturn(0);
4670 }
4671 
4672 /*@C
4673   DMSetPeriodicity - Set the description of mesh periodicity
4674 
4675   Input Parameters:
4676 + dm      - The DM object
4677 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4678 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4679 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4680 - bd      - This describes the type of periodicity in each topological dimension
4681 
4682   Level: developer
4683 
4684 .seealso: DMGetPeriodicity()
4685 @*/
4686 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4687 {
4688   PetscInt       dim, d;
4689   PetscErrorCode ierr;
4690 
4691   PetscFunctionBegin;
4692   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4693   PetscValidLogicalCollectiveBool(dm,per,2);
4694   if (maxCell) {
4695     PetscValidPointer(maxCell,3);
4696     PetscValidPointer(L,4);
4697     PetscValidPointer(bd,5);
4698   }
4699   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4700   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4701   if (maxCell) {
4702     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4703     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4704     dm->periodic = PETSC_TRUE;
4705   } else {
4706     dm->periodic = per;
4707   }
4708   PetscFunctionReturn(0);
4709 }
4710 
4711 /*@
4712   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.
4713 
4714   Input Parameters:
4715 + dm     - The DM
4716 . in     - The input coordinate point (dim numbers)
4717 - endpoint - Include the endpoint L_i
4718 
4719   Output Parameter:
4720 . out - The localized coordinate point
4721 
4722   Level: developer
4723 
4724 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4725 @*/
4726 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4727 {
4728   PetscInt       dim, d;
4729   PetscErrorCode ierr;
4730 
4731   PetscFunctionBegin;
4732   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4733   if (!dm->maxCell) {
4734     for (d = 0; d < dim; ++d) out[d] = in[d];
4735   } else {
4736     if (endpoint) {
4737       for (d = 0; d < dim; ++d) {
4738         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)) {
4739           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4740         } else {
4741           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4742         }
4743       }
4744     } else {
4745       for (d = 0; d < dim; ++d) {
4746         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4747       }
4748     }
4749   }
4750   PetscFunctionReturn(0);
4751 }
4752 
4753 /*
4754   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.
4755 
4756   Input Parameters:
4757 + dm     - The DM
4758 . dim    - The spatial dimension
4759 . anchor - The anchor point, the input point can be no more than maxCell away from it
4760 - in     - The input coordinate point (dim numbers)
4761 
4762   Output Parameter:
4763 . out - The localized coordinate point
4764 
4765   Level: developer
4766 
4767   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
4768 
4769 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4770 */
4771 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4772 {
4773   PetscInt d;
4774 
4775   PetscFunctionBegin;
4776   if (!dm->maxCell) {
4777     for (d = 0; d < dim; ++d) out[d] = in[d];
4778   } else {
4779     for (d = 0; d < dim; ++d) {
4780       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4781         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4782       } else {
4783         out[d] = in[d];
4784       }
4785     }
4786   }
4787   PetscFunctionReturn(0);
4788 }
4789 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4790 {
4791   PetscInt d;
4792 
4793   PetscFunctionBegin;
4794   if (!dm->maxCell) {
4795     for (d = 0; d < dim; ++d) out[d] = in[d];
4796   } else {
4797     for (d = 0; d < dim; ++d) {
4798       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4799         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4800       } else {
4801         out[d] = in[d];
4802       }
4803     }
4804   }
4805   PetscFunctionReturn(0);
4806 }
4807 
4808 /*
4809   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.
4810 
4811   Input Parameters:
4812 + dm     - The DM
4813 . dim    - The spatial dimension
4814 . anchor - The anchor point, the input point can be no more than maxCell away from it
4815 . in     - The input coordinate delta (dim numbers)
4816 - out    - The input coordinate point (dim numbers)
4817 
4818   Output Parameter:
4819 . out    - The localized coordinate in + out
4820 
4821   Level: developer
4822 
4823   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
4824 
4825 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4826 */
4827 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4828 {
4829   PetscInt d;
4830 
4831   PetscFunctionBegin;
4832   if (!dm->maxCell) {
4833     for (d = 0; d < dim; ++d) out[d] += in[d];
4834   } else {
4835     for (d = 0; d < dim; ++d) {
4836       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4837         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4838       } else {
4839         out[d] += in[d];
4840       }
4841     }
4842   }
4843   PetscFunctionReturn(0);
4844 }
4845 
4846 /*@
4847   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4848 
4849   Input Parameter:
4850 . dm - The DM
4851 
4852   Output Parameter:
4853   areLocalized - True if localized
4854 
4855   Level: developer
4856 
4857 .seealso: DMLocalizeCoordinates()
4858 @*/
4859 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4860 {
4861   DM             cdm;
4862   PetscSection   coordSection;
4863   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
4864   PetscBool      isPlex, alreadyLocalized;
4865   PetscErrorCode ierr;
4866 
4867   PetscFunctionBegin;
4868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4869   PetscValidPointer(areLocalized, 2);
4870 
4871   *areLocalized = PETSC_FALSE;
4872   if (!dm->periodic) PetscFunctionReturn(0); /* This is a hideous optimization hack! */
4873 
4874   /* We need some generic way of refering to cells/vertices */
4875   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4876   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4877   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
4878   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4879 
4880   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4881   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
4882   alreadyLocalized = PETSC_FALSE;
4883   for (c = cStart; c < cEnd; ++c) {
4884     if (c < sStart || c >= sEnd) continue;
4885     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4886     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
4887   }
4888   ierr = MPIU_Allreduce(&alreadyLocalized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4889   PetscFunctionReturn(0);
4890 }
4891 
4892 
4893 /*@
4894   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
4895 
4896   Input Parameter:
4897 . dm - The DM
4898 
4899   Level: developer
4900 
4901 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4902 @*/
4903 PetscErrorCode DMLocalizeCoordinates(DM dm)
4904 {
4905   DM             cdm;
4906   PetscSection   coordSection, cSection;
4907   Vec            coordinates,  cVec;
4908   PetscScalar   *coords, *coords2, *anchor, *localized;
4909   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4910   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4911   PetscInt       maxHeight = 0, h;
4912   PetscInt       *pStart = NULL, *pEnd = NULL;
4913   PetscErrorCode ierr;
4914 
4915   PetscFunctionBegin;
4916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4917   if (!dm->periodic) PetscFunctionReturn(0);
4918   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
4919   if (alreadyLocalized) PetscFunctionReturn(0);
4920 
4921   /* We need some generic way of refering to cells/vertices */
4922   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4923   {
4924     PetscBool isplex;
4925 
4926     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4927     if (isplex) {
4928       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4929       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4930       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4931       pEnd = &pStart[maxHeight + 1];
4932       newStart = vStart;
4933       newEnd   = vEnd;
4934       for (h = 0; h <= maxHeight; h++) {
4935         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4936         newStart = PetscMin(newStart,pStart[h]);
4937         newEnd   = PetscMax(newEnd,pEnd[h]);
4938       }
4939     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4940   }
4941   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4942   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
4943   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4944   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4945   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4946 
4947   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4948   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4949   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4950   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4951   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4952 
4953   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4954   localized = &anchor[bs];
4955   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4956   for (h = 0; h <= maxHeight; h++) {
4957     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4958 
4959     for (c = cStart; c < cEnd; ++c) {
4960       PetscScalar *cellCoords = NULL;
4961       PetscInt     b;
4962 
4963       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4964       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4965       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4966       for (d = 0; d < dof/bs; ++d) {
4967         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
4968         for (b = 0; b < bs; b++) {
4969           if (cellCoords[d*bs + b] != localized[b]) break;
4970         }
4971         if (b < bs) break;
4972       }
4973       if (d < dof/bs) {
4974         if (c >= sStart && c < sEnd) {
4975           PetscInt cdof;
4976 
4977           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
4978           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4979         }
4980         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
4981         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
4982       }
4983       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4984     }
4985   }
4986   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4987   if (alreadyLocalizedGlobal) {
4988     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4989     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4990     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4991     PetscFunctionReturn(0);
4992   }
4993   for (v = vStart; v < vEnd; ++v) {
4994     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4995     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
4996     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
4997   }
4998   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
4999   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
5000   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
5001   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
5002   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
5003   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
5004   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
5005   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5006   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
5007   for (v = vStart; v < vEnd; ++v) {
5008     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5009     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5010     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
5011     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
5012   }
5013   for (h = 0; h <= maxHeight; h++) {
5014     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5015 
5016     for (c = cStart; c < cEnd; ++c) {
5017       PetscScalar *cellCoords = NULL;
5018       PetscInt     b, cdof;
5019 
5020       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
5021       if (!cdof) continue;
5022       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5023       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
5024       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5025       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
5026       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5027     }
5028   }
5029   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5030   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5031   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5032   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
5033   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
5034   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
5035   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
5036   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5037   PetscFunctionReturn(0);
5038 }
5039 
5040 /*@
5041   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
5042 
5043   Collective on Vec v (see explanation below)
5044 
5045   Input Parameters:
5046 + dm - The DM
5047 . v - The Vec of points
5048 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
5049 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
5050 
5051   Output Parameter:
5052 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
5053 - cells - The PetscSF containing the ranks and local indices of the containing points.
5054 
5055 
5056   Level: developer
5057 
5058   Notes:
5059   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
5060   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
5061 
5062   If *cellSF is NULL on input, a PetscSF will be created.
5063   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
5064 
5065   An array that maps each point to its containing cell can be obtained with
5066 
5067 $    const PetscSFNode *cells;
5068 $    PetscInt           nFound;
5069 $    const PetscInt    *found;
5070 $
5071 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
5072 
5073   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
5074   the index of the cell in its rank's local numbering.
5075 
5076 .keywords: point location, mesh
5077 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
5078 @*/
5079 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
5080 {
5081   PetscErrorCode ierr;
5082 
5083   PetscFunctionBegin;
5084   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5085   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
5086   PetscValidPointer(cellSF,4);
5087   if (*cellSF) {
5088     PetscMPIInt result;
5089 
5090     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
5091     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
5092     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
5093   } else {
5094     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
5095   }
5096   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5097   if (dm->ops->locatepoints) {
5098     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
5099   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
5100   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5101   PetscFunctionReturn(0);
5102 }
5103 
5104 /*@
5105   DMGetOutputDM - Retrieve the DM associated with the layout for output
5106 
5107   Input Parameter:
5108 . dm - The original DM
5109 
5110   Output Parameter:
5111 . odm - The DM which provides the layout for output
5112 
5113   Level: intermediate
5114 
5115 .seealso: VecView(), DMGetDefaultGlobalSection()
5116 @*/
5117 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
5118 {
5119   PetscSection   section;
5120   PetscBool      hasConstraints, ghasConstraints;
5121   PetscErrorCode ierr;
5122 
5123   PetscFunctionBegin;
5124   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5125   PetscValidPointer(odm,2);
5126   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
5127   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
5128   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
5129   if (!ghasConstraints) {
5130     *odm = dm;
5131     PetscFunctionReturn(0);
5132   }
5133   if (!dm->dmBC) {
5134     PetscDS      ds;
5135     PetscSection newSection, gsection;
5136     PetscSF      sf;
5137 
5138     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
5139     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5140     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
5141     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
5142     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
5143     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
5144     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
5145     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
5146     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
5147     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
5148   }
5149   *odm = dm->dmBC;
5150   PetscFunctionReturn(0);
5151 }
5152 
5153 /*@
5154   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
5155 
5156   Input Parameter:
5157 . dm - The original DM
5158 
5159   Output Parameters:
5160 + num - The output sequence number
5161 - val - The output sequence value
5162 
5163   Level: intermediate
5164 
5165   Note: This is intended for output that should appear in sequence, for instance
5166   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5167 
5168 .seealso: VecView()
5169 @*/
5170 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
5171 {
5172   PetscFunctionBegin;
5173   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5174   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
5175   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
5176   PetscFunctionReturn(0);
5177 }
5178 
5179 /*@
5180   DMSetOutputSequenceNumber - Set the sequence number/value for output
5181 
5182   Input Parameters:
5183 + dm - The original DM
5184 . num - The output sequence number
5185 - val - The output sequence value
5186 
5187   Level: intermediate
5188 
5189   Note: This is intended for output that should appear in sequence, for instance
5190   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5191 
5192 .seealso: VecView()
5193 @*/
5194 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5195 {
5196   PetscFunctionBegin;
5197   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5198   dm->outputSequenceNum = num;
5199   dm->outputSequenceVal = val;
5200   PetscFunctionReturn(0);
5201 }
5202 
5203 /*@C
5204   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
5205 
5206   Input Parameters:
5207 + dm   - The original DM
5208 . name - The sequence name
5209 - num  - The output sequence number
5210 
5211   Output Parameter:
5212 . val  - The output sequence value
5213 
5214   Level: intermediate
5215 
5216   Note: This is intended for output that should appear in sequence, for instance
5217   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5218 
5219 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5220 @*/
5221 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5222 {
5223   PetscBool      ishdf5;
5224   PetscErrorCode ierr;
5225 
5226   PetscFunctionBegin;
5227   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5228   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
5229   PetscValidPointer(val,4);
5230   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
5231   if (ishdf5) {
5232 #if defined(PETSC_HAVE_HDF5)
5233     PetscScalar value;
5234 
5235     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
5236     *val = PetscRealPart(value);
5237 #endif
5238   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5239   PetscFunctionReturn(0);
5240 }
5241 
5242 /*@
5243   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
5244 
5245   Not collective
5246 
5247   Input Parameter:
5248 . dm - The DM
5249 
5250   Output Parameter:
5251 . useNatural - The flag to build the mapping to a natural order during distribution
5252 
5253   Level: beginner
5254 
5255 .seealso: DMSetUseNatural(), DMCreate()
5256 @*/
5257 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5258 {
5259   PetscFunctionBegin;
5260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5261   PetscValidPointer(useNatural, 2);
5262   *useNatural = dm->useNatural;
5263   PetscFunctionReturn(0);
5264 }
5265 
5266 /*@
5267   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
5268 
5269   Collective on dm
5270 
5271   Input Parameters:
5272 + dm - The DM
5273 - useNatural - The flag to build the mapping to a natural order during distribution
5274 
5275   Level: beginner
5276 
5277 .seealso: DMGetUseNatural(), DMCreate()
5278 @*/
5279 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5280 {
5281   PetscFunctionBegin;
5282   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5283   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
5284   dm->useNatural = useNatural;
5285   PetscFunctionReturn(0);
5286 }
5287 
5288 
5289 /*@C
5290   DMCreateLabel - Create a label of the given name if it does not already exist
5291 
5292   Not Collective
5293 
5294   Input Parameters:
5295 + dm   - The DM object
5296 - name - The label name
5297 
5298   Level: intermediate
5299 
5300 .keywords: mesh
5301 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5302 @*/
5303 PetscErrorCode DMCreateLabel(DM dm, const char name[])
5304 {
5305   DMLabelLink    next  = dm->labels->next;
5306   PetscBool      flg   = PETSC_FALSE;
5307   PetscErrorCode ierr;
5308 
5309   PetscFunctionBegin;
5310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5311   PetscValidCharPointer(name, 2);
5312   while (next) {
5313     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5314     if (flg) break;
5315     next = next->next;
5316   }
5317   if (!flg) {
5318     DMLabelLink tmpLabel;
5319 
5320     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5321     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
5322     tmpLabel->output = PETSC_TRUE;
5323     tmpLabel->next   = dm->labels->next;
5324     dm->labels->next = tmpLabel;
5325   }
5326   PetscFunctionReturn(0);
5327 }
5328 
5329 /*@C
5330   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
5331 
5332   Not Collective
5333 
5334   Input Parameters:
5335 + dm   - The DM object
5336 . name - The label name
5337 - point - The mesh point
5338 
5339   Output Parameter:
5340 . value - The label value for this point, or -1 if the point is not in the label
5341 
5342   Level: beginner
5343 
5344 .keywords: mesh
5345 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5346 @*/
5347 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5348 {
5349   DMLabel        label;
5350   PetscErrorCode ierr;
5351 
5352   PetscFunctionBegin;
5353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5354   PetscValidCharPointer(name, 2);
5355   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5356   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5357   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
5358   PetscFunctionReturn(0);
5359 }
5360 
5361 /*@C
5362   DMSetLabelValue - Add a point to a Sieve Label with given value
5363 
5364   Not Collective
5365 
5366   Input Parameters:
5367 + dm   - The DM object
5368 . name - The label name
5369 . point - The mesh point
5370 - value - The label value for this point
5371 
5372   Output Parameter:
5373 
5374   Level: beginner
5375 
5376 .keywords: mesh
5377 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5378 @*/
5379 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5380 {
5381   DMLabel        label;
5382   PetscErrorCode ierr;
5383 
5384   PetscFunctionBegin;
5385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5386   PetscValidCharPointer(name, 2);
5387   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5388   if (!label) {
5389     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
5390     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5391   }
5392   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
5393   PetscFunctionReturn(0);
5394 }
5395 
5396 /*@C
5397   DMClearLabelValue - Remove a point from a Sieve Label with given value
5398 
5399   Not Collective
5400 
5401   Input Parameters:
5402 + dm   - The DM object
5403 . name - The label name
5404 . point - The mesh point
5405 - value - The label value for this point
5406 
5407   Output Parameter:
5408 
5409   Level: beginner
5410 
5411 .keywords: mesh
5412 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5413 @*/
5414 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5415 {
5416   DMLabel        label;
5417   PetscErrorCode ierr;
5418 
5419   PetscFunctionBegin;
5420   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5421   PetscValidCharPointer(name, 2);
5422   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5423   if (!label) PetscFunctionReturn(0);
5424   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5425   PetscFunctionReturn(0);
5426 }
5427 
5428 /*@C
5429   DMGetLabelSize - Get the number of different integer ids in a Label
5430 
5431   Not Collective
5432 
5433   Input Parameters:
5434 + dm   - The DM object
5435 - name - The label name
5436 
5437   Output Parameter:
5438 . size - The number of different integer ids, or 0 if the label does not exist
5439 
5440   Level: beginner
5441 
5442 .keywords: mesh
5443 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5444 @*/
5445 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5446 {
5447   DMLabel        label;
5448   PetscErrorCode ierr;
5449 
5450   PetscFunctionBegin;
5451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5452   PetscValidCharPointer(name, 2);
5453   PetscValidPointer(size, 3);
5454   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5455   *size = 0;
5456   if (!label) PetscFunctionReturn(0);
5457   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5458   PetscFunctionReturn(0);
5459 }
5460 
5461 /*@C
5462   DMGetLabelIdIS - Get the integer ids in a label
5463 
5464   Not Collective
5465 
5466   Input Parameters:
5467 + mesh - The DM object
5468 - name - The label name
5469 
5470   Output Parameter:
5471 . ids - The integer ids, or NULL if the label does not exist
5472 
5473   Level: beginner
5474 
5475 .keywords: mesh
5476 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5477 @*/
5478 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5479 {
5480   DMLabel        label;
5481   PetscErrorCode ierr;
5482 
5483   PetscFunctionBegin;
5484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5485   PetscValidCharPointer(name, 2);
5486   PetscValidPointer(ids, 3);
5487   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5488   *ids = NULL;
5489  if (label) {
5490     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5491   } else {
5492     /* returning an empty IS */
5493     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
5494   }
5495   PetscFunctionReturn(0);
5496 }
5497 
5498 /*@C
5499   DMGetStratumSize - Get the number of points in a label stratum
5500 
5501   Not Collective
5502 
5503   Input Parameters:
5504 + dm - The DM object
5505 . name - The label name
5506 - value - The stratum value
5507 
5508   Output Parameter:
5509 . size - The stratum size
5510 
5511   Level: beginner
5512 
5513 .keywords: mesh
5514 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5515 @*/
5516 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5517 {
5518   DMLabel        label;
5519   PetscErrorCode ierr;
5520 
5521   PetscFunctionBegin;
5522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5523   PetscValidCharPointer(name, 2);
5524   PetscValidPointer(size, 4);
5525   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5526   *size = 0;
5527   if (!label) PetscFunctionReturn(0);
5528   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5529   PetscFunctionReturn(0);
5530 }
5531 
5532 /*@C
5533   DMGetStratumIS - Get the points in a label stratum
5534 
5535   Not Collective
5536 
5537   Input Parameters:
5538 + dm - The DM object
5539 . name - The label name
5540 - value - The stratum value
5541 
5542   Output Parameter:
5543 . points - The stratum points, or NULL if the label does not exist or does not have that value
5544 
5545   Level: beginner
5546 
5547 .keywords: mesh
5548 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5549 @*/
5550 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5551 {
5552   DMLabel        label;
5553   PetscErrorCode ierr;
5554 
5555   PetscFunctionBegin;
5556   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5557   PetscValidCharPointer(name, 2);
5558   PetscValidPointer(points, 4);
5559   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5560   *points = NULL;
5561   if (!label) PetscFunctionReturn(0);
5562   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5563   PetscFunctionReturn(0);
5564 }
5565 
5566 /*@C
5567   DMSetStratumIS - Set the points in a label stratum
5568 
5569   Not Collective
5570 
5571   Input Parameters:
5572 + dm - The DM object
5573 . name - The label name
5574 . value - The stratum value
5575 - points - The stratum points
5576 
5577   Level: beginner
5578 
5579 .keywords: mesh
5580 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5581 @*/
5582 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5583 {
5584   DMLabel        label;
5585   PetscErrorCode ierr;
5586 
5587   PetscFunctionBegin;
5588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5589   PetscValidCharPointer(name, 2);
5590   PetscValidPointer(points, 4);
5591   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5592   if (!label) PetscFunctionReturn(0);
5593   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5594   PetscFunctionReturn(0);
5595 }
5596 
5597 /*@C
5598   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5599 
5600   Not Collective
5601 
5602   Input Parameters:
5603 + dm   - The DM object
5604 . name - The label name
5605 - value - The label value for this point
5606 
5607   Output Parameter:
5608 
5609   Level: beginner
5610 
5611 .keywords: mesh
5612 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5613 @*/
5614 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5615 {
5616   DMLabel        label;
5617   PetscErrorCode ierr;
5618 
5619   PetscFunctionBegin;
5620   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5621   PetscValidCharPointer(name, 2);
5622   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5623   if (!label) PetscFunctionReturn(0);
5624   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5625   PetscFunctionReturn(0);
5626 }
5627 
5628 /*@
5629   DMGetNumLabels - Return the number of labels defined by the mesh
5630 
5631   Not Collective
5632 
5633   Input Parameter:
5634 . dm   - The DM object
5635 
5636   Output Parameter:
5637 . numLabels - the number of Labels
5638 
5639   Level: intermediate
5640 
5641 .keywords: mesh
5642 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5643 @*/
5644 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5645 {
5646   DMLabelLink next = dm->labels->next;
5647   PetscInt  n    = 0;
5648 
5649   PetscFunctionBegin;
5650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5651   PetscValidPointer(numLabels, 2);
5652   while (next) {++n; next = next->next;}
5653   *numLabels = n;
5654   PetscFunctionReturn(0);
5655 }
5656 
5657 /*@C
5658   DMGetLabelName - Return the name of nth label
5659 
5660   Not Collective
5661 
5662   Input Parameters:
5663 + dm - The DM object
5664 - n  - the label number
5665 
5666   Output Parameter:
5667 . name - the label name
5668 
5669   Level: intermediate
5670 
5671 .keywords: mesh
5672 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5673 @*/
5674 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5675 {
5676   DMLabelLink next = dm->labels->next;
5677   PetscInt  l    = 0;
5678 
5679   PetscFunctionBegin;
5680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5681   PetscValidPointer(name, 3);
5682   while (next) {
5683     if (l == n) {
5684       *name = next->label->name;
5685       PetscFunctionReturn(0);
5686     }
5687     ++l;
5688     next = next->next;
5689   }
5690   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5691 }
5692 
5693 /*@C
5694   DMHasLabel - Determine whether the mesh has a label of a given name
5695 
5696   Not Collective
5697 
5698   Input Parameters:
5699 + dm   - The DM object
5700 - name - The label name
5701 
5702   Output Parameter:
5703 . hasLabel - PETSC_TRUE if the label is present
5704 
5705   Level: intermediate
5706 
5707 .keywords: mesh
5708 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5709 @*/
5710 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5711 {
5712   DMLabelLink    next = dm->labels->next;
5713   PetscErrorCode ierr;
5714 
5715   PetscFunctionBegin;
5716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5717   PetscValidCharPointer(name, 2);
5718   PetscValidPointer(hasLabel, 3);
5719   *hasLabel = PETSC_FALSE;
5720   while (next) {
5721     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5722     if (*hasLabel) break;
5723     next = next->next;
5724   }
5725   PetscFunctionReturn(0);
5726 }
5727 
5728 /*@C
5729   DMGetLabel - Return the label of a given name, or NULL
5730 
5731   Not Collective
5732 
5733   Input Parameters:
5734 + dm   - The DM object
5735 - name - The label name
5736 
5737   Output Parameter:
5738 . label - The DMLabel, or NULL if the label is absent
5739 
5740   Level: intermediate
5741 
5742 .keywords: mesh
5743 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5744 @*/
5745 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5746 {
5747   DMLabelLink    next = dm->labels->next;
5748   PetscBool      hasLabel;
5749   PetscErrorCode ierr;
5750 
5751   PetscFunctionBegin;
5752   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5753   PetscValidCharPointer(name, 2);
5754   PetscValidPointer(label, 3);
5755   *label = NULL;
5756   while (next) {
5757     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5758     if (hasLabel) {
5759       *label = next->label;
5760       break;
5761     }
5762     next = next->next;
5763   }
5764   PetscFunctionReturn(0);
5765 }
5766 
5767 /*@C
5768   DMGetLabelByNum - Return the nth label
5769 
5770   Not Collective
5771 
5772   Input Parameters:
5773 + dm - The DM object
5774 - n  - the label number
5775 
5776   Output Parameter:
5777 . label - the label
5778 
5779   Level: intermediate
5780 
5781 .keywords: mesh
5782 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5783 @*/
5784 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5785 {
5786   DMLabelLink next = dm->labels->next;
5787   PetscInt    l    = 0;
5788 
5789   PetscFunctionBegin;
5790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5791   PetscValidPointer(label, 3);
5792   while (next) {
5793     if (l == n) {
5794       *label = next->label;
5795       PetscFunctionReturn(0);
5796     }
5797     ++l;
5798     next = next->next;
5799   }
5800   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5801 }
5802 
5803 /*@C
5804   DMAddLabel - Add the label to this mesh
5805 
5806   Not Collective
5807 
5808   Input Parameters:
5809 + dm   - The DM object
5810 - label - The DMLabel
5811 
5812   Level: developer
5813 
5814 .keywords: mesh
5815 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5816 @*/
5817 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5818 {
5819   DMLabelLink    tmpLabel;
5820   PetscBool      hasLabel;
5821   PetscErrorCode ierr;
5822 
5823   PetscFunctionBegin;
5824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5825   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5826   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5827   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5828   tmpLabel->label  = label;
5829   tmpLabel->output = PETSC_TRUE;
5830   tmpLabel->next   = dm->labels->next;
5831   dm->labels->next = tmpLabel;
5832   PetscFunctionReturn(0);
5833 }
5834 
5835 /*@C
5836   DMRemoveLabel - Remove the label from this mesh
5837 
5838   Not Collective
5839 
5840   Input Parameters:
5841 + dm   - The DM object
5842 - name - The label name
5843 
5844   Output Parameter:
5845 . label - The DMLabel, or NULL if the label is absent
5846 
5847   Level: developer
5848 
5849 .keywords: mesh
5850 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5851 @*/
5852 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5853 {
5854   DMLabelLink    next = dm->labels->next;
5855   DMLabelLink    last = NULL;
5856   PetscBool      hasLabel;
5857   PetscErrorCode ierr;
5858 
5859   PetscFunctionBegin;
5860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5861   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5862   *label = NULL;
5863   if (!hasLabel) PetscFunctionReturn(0);
5864   while (next) {
5865     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5866     if (hasLabel) {
5867       if (last) last->next       = next->next;
5868       else      dm->labels->next = next->next;
5869       next->next = NULL;
5870       *label     = next->label;
5871       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5872       if (hasLabel) {
5873         dm->depthLabel = NULL;
5874       }
5875       ierr = PetscFree(next);CHKERRQ(ierr);
5876       break;
5877     }
5878     last = next;
5879     next = next->next;
5880   }
5881   PetscFunctionReturn(0);
5882 }
5883 
5884 /*@C
5885   DMGetLabelOutput - Get the output flag for a given label
5886 
5887   Not Collective
5888 
5889   Input Parameters:
5890 + dm   - The DM object
5891 - name - The label name
5892 
5893   Output Parameter:
5894 . output - The flag for output
5895 
5896   Level: developer
5897 
5898 .keywords: mesh
5899 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5900 @*/
5901 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5902 {
5903   DMLabelLink    next = dm->labels->next;
5904   PetscErrorCode ierr;
5905 
5906   PetscFunctionBegin;
5907   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5908   PetscValidPointer(name, 2);
5909   PetscValidPointer(output, 3);
5910   while (next) {
5911     PetscBool flg;
5912 
5913     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5914     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5915     next = next->next;
5916   }
5917   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5918 }
5919 
5920 /*@C
5921   DMSetLabelOutput - Set the output flag for a given label
5922 
5923   Not Collective
5924 
5925   Input Parameters:
5926 + dm     - The DM object
5927 . name   - The label name
5928 - output - The flag for output
5929 
5930   Level: developer
5931 
5932 .keywords: mesh
5933 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5934 @*/
5935 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5936 {
5937   DMLabelLink    next = dm->labels->next;
5938   PetscErrorCode ierr;
5939 
5940   PetscFunctionBegin;
5941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5942   PetscValidPointer(name, 2);
5943   while (next) {
5944     PetscBool flg;
5945 
5946     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5947     if (flg) {next->output = output; PetscFunctionReturn(0);}
5948     next = next->next;
5949   }
5950   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5951 }
5952 
5953 
5954 /*@
5955   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5956 
5957   Collective on DM
5958 
5959   Input Parameter:
5960 . dmA - The DM object with initial labels
5961 
5962   Output Parameter:
5963 . dmB - The DM object with copied labels
5964 
5965   Level: intermediate
5966 
5967   Note: This is typically used when interpolating or otherwise adding to a mesh
5968 
5969 .keywords: mesh
5970 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5971 @*/
5972 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5973 {
5974   PetscInt       numLabels, l;
5975   PetscErrorCode ierr;
5976 
5977   PetscFunctionBegin;
5978   if (dmA == dmB) PetscFunctionReturn(0);
5979   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5980   for (l = 0; l < numLabels; ++l) {
5981     DMLabel     label, labelNew;
5982     const char *name;
5983     PetscBool   flg;
5984 
5985     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5986     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5987     if (flg) continue;
5988     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
5989     if (flg) continue;
5990     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5991     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5992     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5993   }
5994   PetscFunctionReturn(0);
5995 }
5996 
5997 /*@
5998   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5999 
6000   Input Parameter:
6001 . dm - The DM object
6002 
6003   Output Parameter:
6004 . cdm - The coarse DM
6005 
6006   Level: intermediate
6007 
6008 .seealso: DMSetCoarseDM()
6009 @*/
6010 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
6011 {
6012   PetscFunctionBegin;
6013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6014   PetscValidPointer(cdm, 2);
6015   *cdm = dm->coarseMesh;
6016   PetscFunctionReturn(0);
6017 }
6018 
6019 /*@
6020   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
6021 
6022   Input Parameters:
6023 + dm - The DM object
6024 - cdm - The coarse DM
6025 
6026   Level: intermediate
6027 
6028 .seealso: DMGetCoarseDM()
6029 @*/
6030 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
6031 {
6032   PetscErrorCode ierr;
6033 
6034   PetscFunctionBegin;
6035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6036   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
6037   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6038   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
6039   dm->coarseMesh = cdm;
6040   PetscFunctionReturn(0);
6041 }
6042 
6043 /*@
6044   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
6045 
6046   Input Parameter:
6047 . dm - The DM object
6048 
6049   Output Parameter:
6050 . fdm - The fine DM
6051 
6052   Level: intermediate
6053 
6054 .seealso: DMSetFineDM()
6055 @*/
6056 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
6057 {
6058   PetscFunctionBegin;
6059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6060   PetscValidPointer(fdm, 2);
6061   *fdm = dm->fineMesh;
6062   PetscFunctionReturn(0);
6063 }
6064 
6065 /*@
6066   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
6067 
6068   Input Parameters:
6069 + dm - The DM object
6070 - fdm - The fine DM
6071 
6072   Level: intermediate
6073 
6074 .seealso: DMGetFineDM()
6075 @*/
6076 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
6077 {
6078   PetscErrorCode ierr;
6079 
6080   PetscFunctionBegin;
6081   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6082   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
6083   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
6084   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
6085   dm->fineMesh = fdm;
6086   PetscFunctionReturn(0);
6087 }
6088 
6089 /*=== DMBoundary code ===*/
6090 
6091 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
6092 {
6093   PetscErrorCode ierr;
6094 
6095   PetscFunctionBegin;
6096   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
6097   PetscFunctionReturn(0);
6098 }
6099 
6100 /*@C
6101   DMAddBoundary - Add a boundary condition to the model
6102 
6103   Input Parameters:
6104 + dm          - The DM, with a PetscDS that matches the problem being constrained
6105 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6106 . name        - The BC name
6107 . labelname   - The label defining constrained points
6108 . field       - The field to constrain
6109 . numcomps    - The number of constrained field components
6110 . comps       - An array of constrained component numbers
6111 . bcFunc      - A pointwise function giving boundary values
6112 . numids      - The number of DMLabel ids for constrained points
6113 . ids         - An array of ids for constrained points
6114 - ctx         - An optional user context for bcFunc
6115 
6116   Options Database Keys:
6117 + -bc_<boundary name> <num> - Overrides the boundary ids
6118 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6119 
6120   Level: developer
6121 
6122 .seealso: DMGetBoundary()
6123 @*/
6124 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)
6125 {
6126   PetscErrorCode ierr;
6127 
6128   PetscFunctionBegin;
6129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6130   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
6131   PetscFunctionReturn(0);
6132 }
6133 
6134 /*@
6135   DMGetNumBoundary - Get the number of registered BC
6136 
6137   Input Parameters:
6138 . dm - The mesh object
6139 
6140   Output Parameters:
6141 . numBd - The number of BC
6142 
6143   Level: intermediate
6144 
6145 .seealso: DMAddBoundary(), DMGetBoundary()
6146 @*/
6147 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
6148 {
6149   PetscErrorCode ierr;
6150 
6151   PetscFunctionBegin;
6152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6153   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
6154   PetscFunctionReturn(0);
6155 }
6156 
6157 /*@C
6158   DMGetBoundary - Get a model boundary condition
6159 
6160   Input Parameters:
6161 + dm          - The mesh object
6162 - bd          - The BC number
6163 
6164   Output Parameters:
6165 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6166 . name        - The BC name
6167 . labelname   - The label defining constrained points
6168 . field       - The field to constrain
6169 . numcomps    - The number of constrained field components
6170 . comps       - An array of constrained component numbers
6171 . bcFunc      - A pointwise function giving boundary values
6172 . numids      - The number of DMLabel ids for constrained points
6173 . ids         - An array of ids for constrained points
6174 - ctx         - An optional user context for bcFunc
6175 
6176   Options Database Keys:
6177 + -bc_<boundary name> <num> - Overrides the boundary ids
6178 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6179 
6180   Level: developer
6181 
6182 .seealso: DMAddBoundary()
6183 @*/
6184 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)
6185 {
6186   PetscErrorCode ierr;
6187 
6188   PetscFunctionBegin;
6189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6190   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
6191   PetscFunctionReturn(0);
6192 }
6193 
6194 static PetscErrorCode DMPopulateBoundary(DM dm)
6195 {
6196   DMBoundary *lastnext;
6197   DSBoundary dsbound;
6198   PetscErrorCode ierr;
6199 
6200   PetscFunctionBegin;
6201   dsbound = dm->prob->boundary;
6202   if (dm->boundary) {
6203     DMBoundary next = dm->boundary;
6204 
6205     /* quick check to see if the PetscDS has changed */
6206     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
6207     /* the PetscDS has changed: tear down and rebuild */
6208     while (next) {
6209       DMBoundary b = next;
6210 
6211       next = b->next;
6212       ierr = PetscFree(b);CHKERRQ(ierr);
6213     }
6214     dm->boundary = NULL;
6215   }
6216 
6217   lastnext = &(dm->boundary);
6218   while (dsbound) {
6219     DMBoundary dmbound;
6220 
6221     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
6222     dmbound->dsboundary = dsbound;
6223     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
6224     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
6225     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6226     *lastnext = dmbound;
6227     lastnext = &(dmbound->next);
6228     dsbound = dsbound->next;
6229   }
6230   PetscFunctionReturn(0);
6231 }
6232 
6233 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6234 {
6235   DMBoundary     b;
6236   PetscErrorCode ierr;
6237 
6238   PetscFunctionBegin;
6239   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6240   PetscValidPointer(isBd, 3);
6241   *isBd = PETSC_FALSE;
6242   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
6243   b = dm->boundary;
6244   while (b && !(*isBd)) {
6245     DMLabel    label = b->label;
6246     DSBoundary dsb = b->dsboundary;
6247 
6248     if (label) {
6249       PetscInt i;
6250 
6251       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6252         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
6253       }
6254     }
6255     b = b->next;
6256   }
6257   PetscFunctionReturn(0);
6258 }
6259 
6260 /*@C
6261   DMProjectFunction - This projects the given function into the function space provided.
6262 
6263   Input Parameters:
6264 + dm      - The DM
6265 . time    - The time
6266 . funcs   - The coordinate functions to evaluate, one per field
6267 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6268 - mode    - The insertion mode for values
6269 
6270   Output Parameter:
6271 . X - vector
6272 
6273    Calling sequence of func:
6274 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
6275 
6276 +  dim - The spatial dimension
6277 .  x   - The coordinates
6278 .  Nf  - The number of fields
6279 .  u   - The output field values
6280 -  ctx - optional user-defined function context
6281 
6282   Level: developer
6283 
6284 .seealso: DMComputeL2Diff()
6285 @*/
6286 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6287 {
6288   Vec            localX;
6289   PetscErrorCode ierr;
6290 
6291   PetscFunctionBegin;
6292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6293   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6294   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6295   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6296   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6297   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6298   PetscFunctionReturn(0);
6299 }
6300 
6301 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6302 {
6303   PetscErrorCode ierr;
6304 
6305   PetscFunctionBegin;
6306   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6307   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6308   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6309   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6310   PetscFunctionReturn(0);
6311 }
6312 
6313 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)
6314 {
6315   Vec            localX;
6316   PetscErrorCode ierr;
6317 
6318   PetscFunctionBegin;
6319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6320   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6321   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6322   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6323   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6324   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6325   PetscFunctionReturn(0);
6326 }
6327 
6328 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)
6329 {
6330   PetscErrorCode ierr;
6331 
6332   PetscFunctionBegin;
6333   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6334   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6335   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6336   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6337   PetscFunctionReturn(0);
6338 }
6339 
6340 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6341                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6342                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6343                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6344                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6345                                    InsertMode mode, Vec localX)
6346 {
6347   PetscErrorCode ierr;
6348 
6349   PetscFunctionBegin;
6350   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6351   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
6352   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
6353   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6354   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
6355   PetscFunctionReturn(0);
6356 }
6357 
6358 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6359                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6360                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6361                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6362                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6363                                         InsertMode mode, Vec localX)
6364 {
6365   PetscErrorCode ierr;
6366 
6367   PetscFunctionBegin;
6368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6369   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
6370   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
6371   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6372   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
6373   PetscFunctionReturn(0);
6374 }
6375 
6376 /*@C
6377   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
6378 
6379   Input Parameters:
6380 + dm    - The DM
6381 . time  - The time
6382 . funcs - The functions to evaluate for each field component
6383 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6384 - X     - The coefficient vector u_h, a global vector
6385 
6386   Output Parameter:
6387 . diff - The diff ||u - u_h||_2
6388 
6389   Level: developer
6390 
6391 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6392 @*/
6393 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6394 {
6395   PetscErrorCode ierr;
6396 
6397   PetscFunctionBegin;
6398   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6399   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6400   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6401   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6402   PetscFunctionReturn(0);
6403 }
6404 
6405 /*@C
6406   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
6407 
6408   Input Parameters:
6409 + dm    - The DM
6410 , time  - The time
6411 . funcs - The gradient functions to evaluate for each field component
6412 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6413 . X     - The coefficient vector u_h, a global vector
6414 - n     - The vector to project along
6415 
6416   Output Parameter:
6417 . diff - The diff ||(grad u - grad u_h) . n||_2
6418 
6419   Level: developer
6420 
6421 .seealso: DMProjectFunction(), DMComputeL2Diff()
6422 @*/
6423 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)
6424 {
6425   PetscErrorCode ierr;
6426 
6427   PetscFunctionBegin;
6428   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6429   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6430   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6431   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6432   PetscFunctionReturn(0);
6433 }
6434 
6435 /*@C
6436   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6437 
6438   Input Parameters:
6439 + dm    - The DM
6440 . time  - The time
6441 . funcs - The functions to evaluate for each field component
6442 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6443 - X     - The coefficient vector u_h, a global vector
6444 
6445   Output Parameter:
6446 . diff - The array of differences, ||u^f - u^f_h||_2
6447 
6448   Level: developer
6449 
6450 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6451 @*/
6452 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6453 {
6454   PetscErrorCode ierr;
6455 
6456   PetscFunctionBegin;
6457   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6458   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6459   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6460   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6461   PetscFunctionReturn(0);
6462 }
6463 
6464 /*@C
6465   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6466                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6467 
6468   Collective on dm
6469 
6470   Input parameters:
6471 + dm - the pre-adaptation DM object
6472 - label - label with the flags
6473 
6474   Output parameters:
6475 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
6476 
6477   Level: intermediate
6478 
6479 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6480 @*/
6481 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6482 {
6483   PetscErrorCode ierr;
6484 
6485   PetscFunctionBegin;
6486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6487   PetscValidPointer(label,2);
6488   PetscValidPointer(dmAdapt,3);
6489   *dmAdapt = NULL;
6490   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6491   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
6492   PetscFunctionReturn(0);
6493 }
6494 
6495 /*@C
6496   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
6497 
6498   Input Parameters:
6499 + dm - The DM object
6500 . metric - The metric to which the mesh is adapted, defined vertex-wise.
6501 - 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_".
6502 
6503   Output Parameter:
6504 . dmAdapt  - Pointer to the DM object containing the adapted mesh
6505 
6506   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
6507 
6508   Level: advanced
6509 
6510 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6511 @*/
6512 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6513 {
6514   PetscErrorCode ierr;
6515 
6516   PetscFunctionBegin;
6517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6518   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
6519   if (bdLabel) PetscValidPointer(bdLabel, 3);
6520   PetscValidPointer(dmAdapt, 4);
6521   *dmAdapt = NULL;
6522   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6523   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
6524   PetscFunctionReturn(0);
6525 }
6526 
6527 /*@C
6528  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6529 
6530  Not Collective
6531 
6532  Input Parameter:
6533  . dm    - The DM
6534 
6535  Output Parameter:
6536  . nranks - the number of neighbours
6537  . ranks - the neighbors ranks
6538 
6539  Notes:
6540  Do not free the array, it is freed when the DM is destroyed.
6541 
6542  Level: beginner
6543 
6544  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6545 @*/
6546 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6547 {
6548   PetscErrorCode ierr;
6549 
6550   PetscFunctionBegin;
6551   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6552   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6553   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6554   PetscFunctionReturn(0);
6555 }
6556 
6557 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6558 
6559 /*
6560     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6561     This has be a different function because it requires DM which is not defined in the Mat library
6562 */
6563 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6564 {
6565   PetscErrorCode ierr;
6566 
6567   PetscFunctionBegin;
6568   if (coloring->ctype == IS_COLORING_LOCAL) {
6569     Vec x1local;
6570     DM  dm;
6571     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6572     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6573     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6574     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6575     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6576     x1   = x1local;
6577   }
6578   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6579   if (coloring->ctype == IS_COLORING_LOCAL) {
6580     DM  dm;
6581     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6582     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6583   }
6584   PetscFunctionReturn(0);
6585 }
6586 
6587 /*@
6588     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6589 
6590     Input Parameter:
6591 .    coloring - the MatFDColoring object
6592 
6593     Developer Notes:
6594     this routine exists because the PETSc Mat library does not know about the DM objects
6595 
6596     Level: advanced
6597 
6598 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6599 @*/
6600 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6601 {
6602   PetscFunctionBegin;
6603   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6604   PetscFunctionReturn(0);
6605 }
6606 
6607 /*@
6608     DMGetCompatibility - determine if two DMs are compatible
6609 
6610     Collective
6611 
6612     Input Parameters:
6613 +    dm - the first DM
6614 -    dm2 - the second DM
6615 
6616     Output Parameters:
6617 +    compatible - whether or not the two DMs are compatible
6618 -    set - whether or not the compatible value was set
6619 
6620     Notes:
6621     Two DMs are deemed compatible if they represent the same parallel decomposition
6622     of the same topology. This implies that the the section (field data) on one
6623     "makes sense" with respect to the topology and parallel decomposition of the other.
6624     Loosely speaking, compatibile DMs represent the same domain, with the same parallel
6625     decomposition, with different data.
6626 
6627     Typically, one would confirm compatibility if intending to simultaneously iterate
6628     over a pair of vectors obtained from different DMs.
6629 
6630     For example, two DMDA objects are compatible if they have the same local
6631     and global sizes and the same stencil width. They can have different numbers
6632     of degrees of freedom per node. Thus, one could use the node numbering from
6633     either DM in bounds for a loop over vectors derived from either DM.
6634 
6635     Consider the operation of summing data living on a 2-dof DMDA to data living
6636     on a 1-dof DMDA, which should be compatible, as in the following snippet.
6637 .vb
6638   ...
6639   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
6640   if (set && compatible)  {
6641     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6642     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6643     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n);CHKERRQ(ierr);
6644     for (j=y; j<y+n; ++j) {
6645       for (i=x; i<x+m, ++i) {
6646         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
6647       }
6648     }
6649     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6650     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6651   } else {
6652     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
6653   }
6654   ...
6655 .ve
6656 
6657     Checking compatibility might be expensive for a given implementation of DM,
6658     or might be impossible to unambiguously confirm or deny. For this reason,
6659     this function may decline to determine compatibility, and hence users should
6660     always check the "set" output parameter.
6661 
6662     A DM is always compatible with itself.
6663 
6664     In the current implementation, DMs which live on "unequal" communicators
6665     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
6666     incompatible.
6667 
6668     This function is labeled "Collective," as information about all subdomains
6669     is required on each rank. However, in DM implementations which store all this
6670     information locally, this function may be merely "Logically Collective".
6671 
6672     Developer Notes:
6673     Compatibility is assumed to be a symmetric concept; if DM A is compatible with DM B,
6674     the DM B is compatible with DM A. Thus, this function checks the implementations
6675     of both dm and dm2 (if they are of different types), attempting to determine
6676     compatibility. It is left to DM implementers to ensure that symmetry is
6677     preserved. The simplest way to do this is, when implementing type-specific
6678     logic for this function, to check for existing logic in the implementation
6679     of other DM types and let *set = PETSC_FALSE if found; the logic of this
6680     function will then call that logic.
6681 
6682     Level: advanced
6683 
6684 .seealso: DM, DMDACreateCompatibleDMDA()
6685 @*/
6686 
6687 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
6688 {
6689   PetscErrorCode ierr;
6690   PetscMPIInt    compareResult;
6691   DMType         type,type2;
6692   PetscBool      sameType;
6693 
6694   PetscFunctionBegin;
6695   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6696   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
6697 
6698   /* Declare a DM compatible with itself */
6699   if (dm == dm2) {
6700     *set = PETSC_TRUE;
6701     *compatible = PETSC_TRUE;
6702     PetscFunctionReturn(0);
6703   }
6704 
6705   /* Declare a DM incompatible with a DM that lives on an "unequal"
6706      communicator. Note that this does not preclude compatibility with
6707      DMs living on "congruent" or "similar" communicators, but this must be
6708      determined by the implementation-specific logic */
6709   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
6710   if (compareResult == MPI_UNEQUAL) {
6711     *set = PETSC_TRUE;
6712     *compatible = PETSC_FALSE;
6713     PetscFunctionReturn(0);
6714   }
6715 
6716   /* Pass to the implementation-specific routine, if one exists. */
6717   if (dm->ops->getcompatibility) {
6718     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
6719     if (*set) {
6720       PetscFunctionReturn(0);
6721     }
6722   }
6723 
6724   /* If dm and dm2 are of different types, then attempt to check compatibility
6725      with an implementation of this function from dm2 */
6726   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
6727   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
6728   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
6729   if (!sameType && dm2->ops->getcompatibility) {
6730     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
6731   } else {
6732     *set = PETSC_FALSE;
6733   }
6734   PetscFunctionReturn(0);
6735 }
6736