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