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