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