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