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