xref: /petsc/src/dm/interface/dm.c (revision 9f4d3c52fa2fe0bb72fec4f4e85d8e495867af35)
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, const 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   PetscInt       dimEmbed;
3888   PetscErrorCode ierr;
3889 
3890   PetscFunctionBegin;
3891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3892   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3893   ierr = PetscObjectReference((PetscObject) prob);CHKERRQ(ierr);
3894   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3895   dm->prob = prob;
3896   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
3897   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
3898   PetscFunctionReturn(0);
3899 }
3900 
3901 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3902 {
3903   PetscErrorCode ierr;
3904 
3905   PetscFunctionBegin;
3906   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3907   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3908   PetscFunctionReturn(0);
3909 }
3910 
3911 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3912 {
3913   PetscInt       Nf, f;
3914   PetscErrorCode ierr;
3915 
3916   PetscFunctionBegin;
3917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3918   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3919   for (f = Nf; f < numFields; ++f) {
3920     PetscContainer obj;
3921 
3922     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3923     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3924     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3925   }
3926   PetscFunctionReturn(0);
3927 }
3928 
3929 /*@
3930   DMGetField - Return the discretization object for a given DM field
3931 
3932   Not collective
3933 
3934   Input Parameters:
3935 + dm - The DM
3936 - f  - The field number
3937 
3938   Output Parameter:
3939 . field - The discretization object
3940 
3941   Level: developer
3942 
3943 .seealso: DMSetField()
3944 @*/
3945 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3946 {
3947   PetscErrorCode ierr;
3948 
3949   PetscFunctionBegin;
3950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3951   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3952   PetscFunctionReturn(0);
3953 }
3954 
3955 /*@
3956   DMSetField - Set the discretization object for a given DM field
3957 
3958   Logically collective on DM
3959 
3960   Input Parameters:
3961 + dm - The DM
3962 . f  - The field number
3963 - field - The discretization object
3964 
3965   Level: developer
3966 
3967 .seealso: DMGetField()
3968 @*/
3969 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3970 {
3971   PetscErrorCode ierr;
3972 
3973   PetscFunctionBegin;
3974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3975   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3976   PetscFunctionReturn(0);
3977 }
3978 
3979 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3980 {
3981   DM dm_coord,dmc_coord;
3982   PetscErrorCode ierr;
3983   Vec coords,ccoords;
3984   Mat inject;
3985   PetscFunctionBegin;
3986   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3987   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3988   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3989   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3990   if (coords && !ccoords) {
3991     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3992     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
3993     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
3994     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
3995     ierr = MatDestroy(&inject);CHKERRQ(ierr);
3996     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3997     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3998   }
3999   PetscFunctionReturn(0);
4000 }
4001 
4002 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
4003 {
4004   DM dm_coord,subdm_coord;
4005   PetscErrorCode ierr;
4006   Vec coords,ccoords,clcoords;
4007   VecScatter *scat_i,*scat_g;
4008   PetscFunctionBegin;
4009   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
4010   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
4011   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
4012   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
4013   if (coords && !ccoords) {
4014     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
4015     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
4016     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
4017     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
4018     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
4019     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4020     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4021     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4022     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4023     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
4024     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
4025     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
4026     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
4027     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
4028     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
4029     ierr = PetscFree(scat_i);CHKERRQ(ierr);
4030     ierr = PetscFree(scat_g);CHKERRQ(ierr);
4031   }
4032   PetscFunctionReturn(0);
4033 }
4034 
4035 /*@
4036   DMGetDimension - Return the topological dimension of the DM
4037 
4038   Not collective
4039 
4040   Input Parameter:
4041 . dm - The DM
4042 
4043   Output Parameter:
4044 . dim - The topological dimension
4045 
4046   Level: beginner
4047 
4048 .seealso: DMSetDimension(), DMCreate()
4049 @*/
4050 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
4051 {
4052   PetscFunctionBegin;
4053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4054   PetscValidPointer(dim, 2);
4055   *dim = dm->dim;
4056   PetscFunctionReturn(0);
4057 }
4058 
4059 /*@
4060   DMSetDimension - Set the topological dimension of the DM
4061 
4062   Collective on dm
4063 
4064   Input Parameters:
4065 + dm - The DM
4066 - dim - The topological dimension
4067 
4068   Level: beginner
4069 
4070 .seealso: DMGetDimension(), DMCreate()
4071 @*/
4072 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
4073 {
4074   PetscErrorCode ierr;
4075 
4076   PetscFunctionBegin;
4077   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4078   PetscValidLogicalCollectiveInt(dm, dim, 2);
4079   dm->dim = dim;
4080   if (dm->prob->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dim);CHKERRQ(ierr);}
4081   PetscFunctionReturn(0);
4082 }
4083 
4084 /*@
4085   DMGetDimPoints - Get the half-open interval for all points of a given dimension
4086 
4087   Collective on DM
4088 
4089   Input Parameters:
4090 + dm - the DM
4091 - dim - the dimension
4092 
4093   Output Parameters:
4094 + pStart - The first point of the given dimension
4095 . pEnd - The first point following points of the given dimension
4096 
4097   Note:
4098   The points are vertices in the Hasse diagram encoding the topology. This is explained in
4099   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
4100   then the interval is empty.
4101 
4102   Level: intermediate
4103 
4104 .keywords: point, Hasse Diagram, dimension
4105 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
4106 @*/
4107 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4108 {
4109   PetscInt       d;
4110   PetscErrorCode ierr;
4111 
4112   PetscFunctionBegin;
4113   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4114   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
4115   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
4116   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
4117   PetscFunctionReturn(0);
4118 }
4119 
4120 /*@
4121   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
4122 
4123   Collective on DM
4124 
4125   Input Parameters:
4126 + dm - the DM
4127 - c - coordinate vector
4128 
4129   Note:
4130   The coordinates do include those for ghost points, which are in the local vector
4131 
4132   Level: intermediate
4133 
4134 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4135 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
4136 @*/
4137 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4138 {
4139   PetscErrorCode ierr;
4140 
4141   PetscFunctionBegin;
4142   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4143   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4144   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4145   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4146   dm->coordinates = c;
4147   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4148   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4149   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4150   PetscFunctionReturn(0);
4151 }
4152 
4153 /*@
4154   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
4155 
4156   Collective on DM
4157 
4158    Input Parameters:
4159 +  dm - the DM
4160 -  c - coordinate vector
4161 
4162   Note:
4163   The coordinates of ghost points can be set using DMSetCoordinates()
4164   followed by DMGetCoordinatesLocal(). This is intended to enable the
4165   setting of ghost coordinates outside of the domain.
4166 
4167   Level: intermediate
4168 
4169 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4170 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4171 @*/
4172 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4173 {
4174   PetscErrorCode ierr;
4175 
4176   PetscFunctionBegin;
4177   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4178   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4179   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4180   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4181 
4182   dm->coordinatesLocal = c;
4183 
4184   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4185   PetscFunctionReturn(0);
4186 }
4187 
4188 /*@
4189   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
4190 
4191   Not Collective
4192 
4193   Input Parameter:
4194 . dm - the DM
4195 
4196   Output Parameter:
4197 . c - global coordinate vector
4198 
4199   Note:
4200   This is a borrowed reference, so the user should NOT destroy this vector
4201 
4202   Each process has only the local coordinates (does NOT have the ghost coordinates).
4203 
4204   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4205   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4206 
4207   Level: intermediate
4208 
4209 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4210 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4211 @*/
4212 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4213 {
4214   PetscErrorCode ierr;
4215 
4216   PetscFunctionBegin;
4217   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4218   PetscValidPointer(c,2);
4219   if (!dm->coordinates && dm->coordinatesLocal) {
4220     DM cdm = NULL;
4221 
4222     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4223     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4224     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4225     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4226     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4227   }
4228   *c = dm->coordinates;
4229   PetscFunctionReturn(0);
4230 }
4231 
4232 /*@
4233   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4234 
4235   Collective on DM
4236 
4237   Input Parameter:
4238 . dm - the DM
4239 
4240   Output Parameter:
4241 . c - coordinate vector
4242 
4243   Note:
4244   This is a borrowed reference, so the user should NOT destroy this vector
4245 
4246   Each process has the local and ghost coordinates
4247 
4248   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4249   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4250 
4251   Level: intermediate
4252 
4253 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4254 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4255 @*/
4256 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4257 {
4258   PetscErrorCode ierr;
4259 
4260   PetscFunctionBegin;
4261   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4262   PetscValidPointer(c,2);
4263   if (!dm->coordinatesLocal && dm->coordinates) {
4264     DM cdm = NULL;
4265 
4266     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4267     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4268     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4269     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4270     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4271   }
4272   *c = dm->coordinatesLocal;
4273   PetscFunctionReturn(0);
4274 }
4275 
4276 /*@
4277   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4278 
4279   Collective on DM
4280 
4281   Input Parameter:
4282 . dm - the DM
4283 
4284   Output Parameter:
4285 . cdm - coordinate DM
4286 
4287   Level: intermediate
4288 
4289 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4290 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4291 @*/
4292 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4293 {
4294   PetscErrorCode ierr;
4295 
4296   PetscFunctionBegin;
4297   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4298   PetscValidPointer(cdm,2);
4299   if (!dm->coordinateDM) {
4300     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4301     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4302   }
4303   *cdm = dm->coordinateDM;
4304   PetscFunctionReturn(0);
4305 }
4306 
4307 /*@
4308   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4309 
4310   Logically Collective on DM
4311 
4312   Input Parameters:
4313 + dm - the DM
4314 - cdm - coordinate DM
4315 
4316   Level: intermediate
4317 
4318 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4319 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4320 @*/
4321 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4322 {
4323   PetscErrorCode ierr;
4324 
4325   PetscFunctionBegin;
4326   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4327   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4328   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4329   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4330   dm->coordinateDM = cdm;
4331   PetscFunctionReturn(0);
4332 }
4333 
4334 /*@
4335   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4336 
4337   Not Collective
4338 
4339   Input Parameter:
4340 . dm - The DM object
4341 
4342   Output Parameter:
4343 . dim - The embedding dimension
4344 
4345   Level: intermediate
4346 
4347 .keywords: mesh, coordinates
4348 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4349 @*/
4350 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4351 {
4352   PetscFunctionBegin;
4353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4354   PetscValidPointer(dim, 2);
4355   if (dm->dimEmbed == PETSC_DEFAULT) {
4356     dm->dimEmbed = dm->dim;
4357   }
4358   *dim = dm->dimEmbed;
4359   PetscFunctionReturn(0);
4360 }
4361 
4362 /*@
4363   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4364 
4365   Not Collective
4366 
4367   Input Parameters:
4368 + dm  - The DM object
4369 - dim - The embedding dimension
4370 
4371   Level: intermediate
4372 
4373 .keywords: mesh, coordinates
4374 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4375 @*/
4376 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4377 {
4378   PetscErrorCode ierr;
4379 
4380   PetscFunctionBegin;
4381   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4382   dm->dimEmbed = dim;
4383   ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);CHKERRQ(ierr);
4384   PetscFunctionReturn(0);
4385 }
4386 
4387 /*@
4388   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4389 
4390   Not Collective
4391 
4392   Input Parameter:
4393 . dm - The DM object
4394 
4395   Output Parameter:
4396 . section - The PetscSection object
4397 
4398   Level: intermediate
4399 
4400 .keywords: mesh, coordinates
4401 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4402 @*/
4403 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4404 {
4405   DM             cdm;
4406   PetscErrorCode ierr;
4407 
4408   PetscFunctionBegin;
4409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4410   PetscValidPointer(section, 2);
4411   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4412   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4413   PetscFunctionReturn(0);
4414 }
4415 
4416 /*@
4417   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4418 
4419   Not Collective
4420 
4421   Input Parameters:
4422 + dm      - The DM object
4423 . dim     - The embedding dimension, or PETSC_DETERMINE
4424 - section - The PetscSection object
4425 
4426   Level: intermediate
4427 
4428 .keywords: mesh, coordinates
4429 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4430 @*/
4431 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4432 {
4433   DM             cdm;
4434   PetscErrorCode ierr;
4435 
4436   PetscFunctionBegin;
4437   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4438   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4439   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4440   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4441   if (dim == PETSC_DETERMINE) {
4442     PetscInt d = PETSC_DEFAULT;
4443     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4444 
4445     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4446     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4447     pStart = PetscMax(vStart, pStart);
4448     pEnd   = PetscMin(vEnd, pEnd);
4449     for (v = pStart; v < pEnd; ++v) {
4450       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4451       if (dd) {d = dd; break;}
4452     }
4453     if (d < 0) d = PETSC_DEFAULT;
4454     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4455   }
4456   PetscFunctionReturn(0);
4457 }
4458 
4459 /*@C
4460   DMGetPeriodicity - Get the description of mesh periodicity
4461 
4462   Input Parameters:
4463 . dm      - The DM object
4464 
4465   Output Parameters:
4466 + per     - Whether the DM is periodic or not
4467 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4468 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4469 - bd      - This describes the type of periodicity in each topological dimension
4470 
4471   Level: developer
4472 
4473 .seealso: DMGetPeriodicity()
4474 @*/
4475 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4476 {
4477   PetscFunctionBegin;
4478   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4479   if (per)     *per     = dm->periodic;
4480   if (L)       *L       = dm->L;
4481   if (maxCell) *maxCell = dm->maxCell;
4482   if (bd)      *bd      = dm->bdtype;
4483   PetscFunctionReturn(0);
4484 }
4485 
4486 /*@C
4487   DMSetPeriodicity - Set the description of mesh periodicity
4488 
4489   Input Parameters:
4490 + dm      - The DM object
4491 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4492 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4493 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4494 - bd      - This describes the type of periodicity in each topological dimension
4495 
4496   Level: developer
4497 
4498 .seealso: DMGetPeriodicity()
4499 @*/
4500 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4501 {
4502   PetscInt       dim, d;
4503   PetscErrorCode ierr;
4504 
4505   PetscFunctionBegin;
4506   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4507   PetscValidLogicalCollectiveBool(dm,per,2);
4508   if (maxCell) {
4509     PetscValidPointer(maxCell,3);
4510     PetscValidPointer(L,4);
4511     PetscValidPointer(bd,5);
4512   }
4513   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4514   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4515   if (maxCell) {
4516     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4517     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4518     dm->periodic = PETSC_TRUE;
4519   } else {
4520     dm->periodic = per;
4521   }
4522   PetscFunctionReturn(0);
4523 }
4524 
4525 /*@
4526   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.
4527 
4528   Input Parameters:
4529 + dm     - The DM
4530 . in     - The input coordinate point (dim numbers)
4531 - endpoint - Include the endpoint L_i
4532 
4533   Output Parameter:
4534 . out - The localized coordinate point
4535 
4536   Level: developer
4537 
4538 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4539 @*/
4540 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4541 {
4542   PetscInt       dim, d;
4543   PetscErrorCode ierr;
4544 
4545   PetscFunctionBegin;
4546   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4547   if (!dm->maxCell) {
4548     for (d = 0; d < dim; ++d) out[d] = in[d];
4549   } else {
4550     if (endpoint) {
4551       for (d = 0; d < dim; ++d) {
4552         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)) {
4553           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4554         } else {
4555           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4556         }
4557       }
4558     } else {
4559       for (d = 0; d < dim; ++d) {
4560         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4561       }
4562     }
4563   }
4564   PetscFunctionReturn(0);
4565 }
4566 
4567 /*
4568   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.
4569 
4570   Input Parameters:
4571 + dm     - The DM
4572 . dim    - The spatial dimension
4573 . anchor - The anchor point, the input point can be no more than maxCell away from it
4574 - in     - The input coordinate point (dim numbers)
4575 
4576   Output Parameter:
4577 . out - The localized coordinate point
4578 
4579   Level: developer
4580 
4581   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
4582 
4583 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4584 */
4585 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4586 {
4587   PetscInt d;
4588 
4589   PetscFunctionBegin;
4590   if (!dm->maxCell) {
4591     for (d = 0; d < dim; ++d) out[d] = in[d];
4592   } else {
4593     for (d = 0; d < dim; ++d) {
4594       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4595         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4596       } else {
4597         out[d] = in[d];
4598       }
4599     }
4600   }
4601   PetscFunctionReturn(0);
4602 }
4603 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4604 {
4605   PetscInt d;
4606 
4607   PetscFunctionBegin;
4608   if (!dm->maxCell) {
4609     for (d = 0; d < dim; ++d) out[d] = in[d];
4610   } else {
4611     for (d = 0; d < dim; ++d) {
4612       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4613         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4614       } else {
4615         out[d] = in[d];
4616       }
4617     }
4618   }
4619   PetscFunctionReturn(0);
4620 }
4621 
4622 /*
4623   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.
4624 
4625   Input Parameters:
4626 + dm     - The DM
4627 . dim    - The spatial dimension
4628 . anchor - The anchor point, the input point can be no more than maxCell away from it
4629 . in     - The input coordinate delta (dim numbers)
4630 - out    - The input coordinate point (dim numbers)
4631 
4632   Output Parameter:
4633 . out    - The localized coordinate in + out
4634 
4635   Level: developer
4636 
4637   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
4638 
4639 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4640 */
4641 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4642 {
4643   PetscInt d;
4644 
4645   PetscFunctionBegin;
4646   if (!dm->maxCell) {
4647     for (d = 0; d < dim; ++d) out[d] += in[d];
4648   } else {
4649     for (d = 0; d < dim; ++d) {
4650       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4651         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4652       } else {
4653         out[d] += in[d];
4654       }
4655     }
4656   }
4657   PetscFunctionReturn(0);
4658 }
4659 
4660 /*@
4661   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4662 
4663   Input Parameter:
4664 . dm - The DM
4665 
4666   Output Parameter:
4667   areLocalized - True if localized
4668 
4669   Level: developer
4670 
4671 .seealso: DMLocalizeCoordinates()
4672 @*/
4673 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4674 {
4675   DM             cdm;
4676   PetscSection   coordSection;
4677   PetscInt       cStart, cEnd, c, sStart, sEnd, dof;
4678   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4679   PetscErrorCode ierr;
4680 
4681   PetscFunctionBegin;
4682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4683   if (!dm->periodic) {
4684     *areLocalized = PETSC_FALSE;
4685     PetscFunctionReturn(0);
4686   }
4687   /* We need some generic way of refering to cells/vertices */
4688   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4689   {
4690     PetscBool isplex;
4691 
4692     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4693     if (isplex) {
4694       ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4695     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4696   }
4697   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4698   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4699   alreadyLocalized = alreadyLocalizedGlobal = PETSC_FALSE;
4700   for (c = cStart; c < cEnd; ++c) {
4701     if (c < sStart || c >= sEnd) {
4702       alreadyLocalized = PETSC_FALSE;
4703       break;
4704     }
4705     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4706     if (dof) {
4707       alreadyLocalized = PETSC_TRUE;
4708       break;
4709     }
4710   }
4711   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4712   *areLocalized = alreadyLocalizedGlobal;
4713   PetscFunctionReturn(0);
4714 }
4715 
4716 
4717 /*@
4718   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
4719 
4720   Input Parameter:
4721 . dm - The DM
4722 
4723   Level: developer
4724 
4725 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4726 @*/
4727 PetscErrorCode DMLocalizeCoordinates(DM dm)
4728 {
4729   DM             cdm;
4730   PetscSection   coordSection, cSection;
4731   Vec            coordinates,  cVec;
4732   PetscScalar   *coords, *coords2, *anchor, *localized;
4733   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4734   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4735   PetscInt       maxHeight = 0, h;
4736   PetscInt       *pStart = NULL, *pEnd = NULL;
4737   PetscErrorCode ierr;
4738 
4739   PetscFunctionBegin;
4740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4741   if (!dm->periodic) PetscFunctionReturn(0);
4742   /* We need some generic way of refering to cells/vertices */
4743   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4744   {
4745     PetscBool isplex;
4746 
4747     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4748     if (isplex) {
4749       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4750       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4751       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4752       pEnd = &pStart[maxHeight + 1];
4753       newStart = vStart;
4754       newEnd   = vEnd;
4755       for (h = 0; h <= maxHeight; h++) {
4756         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4757         newStart = PetscMin(newStart,pStart[h]);
4758         newEnd   = PetscMax(newEnd,pEnd[h]);
4759       }
4760     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4761   }
4762   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4763   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4764   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4765   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4766 
4767   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4768   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4769   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4770   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4771   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4772 
4773   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4774   localized = &anchor[bs];
4775   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4776   for (h = 0; h <= maxHeight; h++) {
4777     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4778 
4779     for (c = cStart; c < cEnd; ++c) {
4780       PetscScalar *cellCoords = NULL;
4781       PetscInt     b;
4782 
4783       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4784       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4785       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4786       for (d = 0; d < dof/bs; ++d) {
4787         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
4788         for (b = 0; b < bs; b++) {
4789           if (cellCoords[d*bs + b] != localized[b]) break;
4790         }
4791         if (b < bs) break;
4792       }
4793       if (d < dof/bs) {
4794         if (c >= sStart && c < sEnd) {
4795           PetscInt cdof;
4796 
4797           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
4798           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4799         }
4800         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
4801         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
4802       }
4803       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4804     }
4805   }
4806   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4807   if (alreadyLocalizedGlobal) {
4808     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4809     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4810     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4811     PetscFunctionReturn(0);
4812   }
4813   for (v = vStart; v < vEnd; ++v) {
4814     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4815     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
4816     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
4817   }
4818   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
4819   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
4820   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
4821   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
4822   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
4823   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4824   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
4825   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4826   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
4827   for (v = vStart; v < vEnd; ++v) {
4828     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4829     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4830     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
4831     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
4832   }
4833   for (h = 0; h <= maxHeight; h++) {
4834     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4835 
4836     for (c = cStart; c < cEnd; ++c) {
4837       PetscScalar *cellCoords = NULL;
4838       PetscInt     b, cdof;
4839 
4840       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
4841       if (!cdof) continue;
4842       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4843       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
4844       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4845       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
4846       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4847     }
4848   }
4849   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4850   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4851   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4852   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
4853   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
4854   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
4855   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
4856   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4857   PetscFunctionReturn(0);
4858 }
4859 
4860 /*@
4861   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
4862 
4863   Collective on Vec v (see explanation below)
4864 
4865   Input Parameters:
4866 + dm - The DM
4867 . v - The Vec of points
4868 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
4869 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
4870 
4871   Output Parameter:
4872 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
4873 - cells - The PetscSF containing the ranks and local indices of the containing points.
4874 
4875 
4876   Level: developer
4877 
4878   Notes:
4879   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
4880   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
4881 
4882   If *cellSF is NULL on input, a PetscSF will be created.
4883   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
4884 
4885   An array that maps each point to its containing cell can be obtained with
4886 
4887 $    const PetscSFNode *cells;
4888 $    PetscInt           nFound;
4889 $    const PetscSFNode *found;
4890 $
4891 $    PetscSFGetGraph(cells,NULL,&nFound,&found,&cells);
4892 
4893   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
4894   the index of the cell in its rank's local numbering.
4895 
4896 .keywords: point location, mesh
4897 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
4898 @*/
4899 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
4900 {
4901   PetscErrorCode ierr;
4902 
4903   PetscFunctionBegin;
4904   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4905   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4906   PetscValidPointer(cellSF,4);
4907   if (*cellSF) {
4908     PetscMPIInt result;
4909 
4910     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
4911     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
4912     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
4913   } else {
4914     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
4915   }
4916   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4917   if (dm->ops->locatepoints) {
4918     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
4919   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4920   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4921   PetscFunctionReturn(0);
4922 }
4923 
4924 /*@
4925   DMGetOutputDM - Retrieve the DM associated with the layout for output
4926 
4927   Input Parameter:
4928 . dm - The original DM
4929 
4930   Output Parameter:
4931 . odm - The DM which provides the layout for output
4932 
4933   Level: intermediate
4934 
4935 .seealso: VecView(), DMGetDefaultGlobalSection()
4936 @*/
4937 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4938 {
4939   PetscSection   section;
4940   PetscBool      hasConstraints, ghasConstraints;
4941   PetscErrorCode ierr;
4942 
4943   PetscFunctionBegin;
4944   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4945   PetscValidPointer(odm,2);
4946   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4947   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4948   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
4949   if (!ghasConstraints) {
4950     *odm = dm;
4951     PetscFunctionReturn(0);
4952   }
4953   if (!dm->dmBC) {
4954     PetscDS      ds;
4955     PetscSection newSection, gsection;
4956     PetscSF      sf;
4957 
4958     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4959     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
4960     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
4961     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4962     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4963     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4964     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4965     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
4966     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4967     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4968   }
4969   *odm = dm->dmBC;
4970   PetscFunctionReturn(0);
4971 }
4972 
4973 /*@
4974   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4975 
4976   Input Parameter:
4977 . dm - The original DM
4978 
4979   Output Parameters:
4980 + num - The output sequence number
4981 - val - The output sequence value
4982 
4983   Level: intermediate
4984 
4985   Note: This is intended for output that should appear in sequence, for instance
4986   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4987 
4988 .seealso: VecView()
4989 @*/
4990 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4991 {
4992   PetscFunctionBegin;
4993   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4994   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4995   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4996   PetscFunctionReturn(0);
4997 }
4998 
4999 /*@
5000   DMSetOutputSequenceNumber - Set the sequence number/value for output
5001 
5002   Input Parameters:
5003 + dm - The original DM
5004 . num - The output sequence number
5005 - val - The output sequence value
5006 
5007   Level: intermediate
5008 
5009   Note: This is intended for output that should appear in sequence, for instance
5010   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5011 
5012 .seealso: VecView()
5013 @*/
5014 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5015 {
5016   PetscFunctionBegin;
5017   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5018   dm->outputSequenceNum = num;
5019   dm->outputSequenceVal = val;
5020   PetscFunctionReturn(0);
5021 }
5022 
5023 /*@C
5024   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
5025 
5026   Input Parameters:
5027 + dm   - The original DM
5028 . name - The sequence name
5029 - num  - The output sequence number
5030 
5031   Output Parameter:
5032 . val  - The output sequence value
5033 
5034   Level: intermediate
5035 
5036   Note: This is intended for output that should appear in sequence, for instance
5037   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5038 
5039 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5040 @*/
5041 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5042 {
5043   PetscBool      ishdf5;
5044   PetscErrorCode ierr;
5045 
5046   PetscFunctionBegin;
5047   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5048   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
5049   PetscValidPointer(val,4);
5050   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
5051   if (ishdf5) {
5052 #if defined(PETSC_HAVE_HDF5)
5053     PetscScalar value;
5054 
5055     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
5056     *val = PetscRealPart(value);
5057 #endif
5058   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5059   PetscFunctionReturn(0);
5060 }
5061 
5062 /*@
5063   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
5064 
5065   Not collective
5066 
5067   Input Parameter:
5068 . dm - The DM
5069 
5070   Output Parameter:
5071 . useNatural - The flag to build the mapping to a natural order during distribution
5072 
5073   Level: beginner
5074 
5075 .seealso: DMSetUseNatural(), DMCreate()
5076 @*/
5077 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5078 {
5079   PetscFunctionBegin;
5080   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5081   PetscValidPointer(useNatural, 2);
5082   *useNatural = dm->useNatural;
5083   PetscFunctionReturn(0);
5084 }
5085 
5086 /*@
5087   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
5088 
5089   Collective on dm
5090 
5091   Input Parameters:
5092 + dm - The DM
5093 - useNatural - The flag to build the mapping to a natural order during distribution
5094 
5095   Level: beginner
5096 
5097 .seealso: DMGetUseNatural(), DMCreate()
5098 @*/
5099 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5100 {
5101   PetscFunctionBegin;
5102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5103   PetscValidLogicalCollectiveInt(dm, useNatural, 2);
5104   dm->useNatural = useNatural;
5105   PetscFunctionReturn(0);
5106 }
5107 
5108 
5109 /*@C
5110   DMCreateLabel - Create a label of the given name if it does not already exist
5111 
5112   Not Collective
5113 
5114   Input Parameters:
5115 + dm   - The DM object
5116 - name - The label name
5117 
5118   Level: intermediate
5119 
5120 .keywords: mesh
5121 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5122 @*/
5123 PetscErrorCode DMCreateLabel(DM dm, const char name[])
5124 {
5125   DMLabelLink    next  = dm->labels->next;
5126   PetscBool      flg   = PETSC_FALSE;
5127   PetscErrorCode ierr;
5128 
5129   PetscFunctionBegin;
5130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5131   PetscValidCharPointer(name, 2);
5132   while (next) {
5133     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5134     if (flg) break;
5135     next = next->next;
5136   }
5137   if (!flg) {
5138     DMLabelLink tmpLabel;
5139 
5140     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5141     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
5142     tmpLabel->output = PETSC_TRUE;
5143     tmpLabel->next   = dm->labels->next;
5144     dm->labels->next = tmpLabel;
5145   }
5146   PetscFunctionReturn(0);
5147 }
5148 
5149 /*@C
5150   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
5151 
5152   Not Collective
5153 
5154   Input Parameters:
5155 + dm   - The DM object
5156 . name - The label name
5157 - point - The mesh point
5158 
5159   Output Parameter:
5160 . value - The label value for this point, or -1 if the point is not in the label
5161 
5162   Level: beginner
5163 
5164 .keywords: mesh
5165 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5166 @*/
5167 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5168 {
5169   DMLabel        label;
5170   PetscErrorCode ierr;
5171 
5172   PetscFunctionBegin;
5173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5174   PetscValidCharPointer(name, 2);
5175   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5176   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5177   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
5178   PetscFunctionReturn(0);
5179 }
5180 
5181 /*@C
5182   DMSetLabelValue - Add a point to a Sieve Label with given value
5183 
5184   Not Collective
5185 
5186   Input Parameters:
5187 + dm   - The DM object
5188 . name - The label name
5189 . point - The mesh point
5190 - value - The label value for this point
5191 
5192   Output Parameter:
5193 
5194   Level: beginner
5195 
5196 .keywords: mesh
5197 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5198 @*/
5199 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5200 {
5201   DMLabel        label;
5202   PetscErrorCode ierr;
5203 
5204   PetscFunctionBegin;
5205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5206   PetscValidCharPointer(name, 2);
5207   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5208   if (!label) {
5209     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
5210     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5211   }
5212   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
5213   PetscFunctionReturn(0);
5214 }
5215 
5216 /*@C
5217   DMClearLabelValue - Remove a point from a Sieve Label with given value
5218 
5219   Not Collective
5220 
5221   Input Parameters:
5222 + dm   - The DM object
5223 . name - The label name
5224 . point - The mesh point
5225 - value - The label value for this point
5226 
5227   Output Parameter:
5228 
5229   Level: beginner
5230 
5231 .keywords: mesh
5232 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5233 @*/
5234 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5235 {
5236   DMLabel        label;
5237   PetscErrorCode ierr;
5238 
5239   PetscFunctionBegin;
5240   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5241   PetscValidCharPointer(name, 2);
5242   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5243   if (!label) PetscFunctionReturn(0);
5244   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5245   PetscFunctionReturn(0);
5246 }
5247 
5248 /*@C
5249   DMGetLabelSize - Get the number of different integer ids in a Label
5250 
5251   Not Collective
5252 
5253   Input Parameters:
5254 + dm   - The DM object
5255 - name - The label name
5256 
5257   Output Parameter:
5258 . size - The number of different integer ids, or 0 if the label does not exist
5259 
5260   Level: beginner
5261 
5262 .keywords: mesh
5263 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5264 @*/
5265 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5266 {
5267   DMLabel        label;
5268   PetscErrorCode ierr;
5269 
5270   PetscFunctionBegin;
5271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5272   PetscValidCharPointer(name, 2);
5273   PetscValidPointer(size, 3);
5274   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5275   *size = 0;
5276   if (!label) PetscFunctionReturn(0);
5277   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5278   PetscFunctionReturn(0);
5279 }
5280 
5281 /*@C
5282   DMGetLabelIdIS - Get the integer ids in a label
5283 
5284   Not Collective
5285 
5286   Input Parameters:
5287 + mesh - The DM object
5288 - name - The label name
5289 
5290   Output Parameter:
5291 . ids - The integer ids, or NULL if the label does not exist
5292 
5293   Level: beginner
5294 
5295 .keywords: mesh
5296 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5297 @*/
5298 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5299 {
5300   DMLabel        label;
5301   PetscErrorCode ierr;
5302 
5303   PetscFunctionBegin;
5304   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5305   PetscValidCharPointer(name, 2);
5306   PetscValidPointer(ids, 3);
5307   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5308   *ids = NULL;
5309   if (!label) PetscFunctionReturn(0);
5310   ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5311   PetscFunctionReturn(0);
5312 }
5313 
5314 /*@C
5315   DMGetStratumSize - Get the number of points in a label stratum
5316 
5317   Not Collective
5318 
5319   Input Parameters:
5320 + dm - The DM object
5321 . name - The label name
5322 - value - The stratum value
5323 
5324   Output Parameter:
5325 . size - The stratum size
5326 
5327   Level: beginner
5328 
5329 .keywords: mesh
5330 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5331 @*/
5332 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5333 {
5334   DMLabel        label;
5335   PetscErrorCode ierr;
5336 
5337   PetscFunctionBegin;
5338   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5339   PetscValidCharPointer(name, 2);
5340   PetscValidPointer(size, 4);
5341   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5342   *size = 0;
5343   if (!label) PetscFunctionReturn(0);
5344   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5345   PetscFunctionReturn(0);
5346 }
5347 
5348 /*@C
5349   DMGetStratumIS - Get the points in a label stratum
5350 
5351   Not Collective
5352 
5353   Input Parameters:
5354 + dm - The DM object
5355 . name - The label name
5356 - value - The stratum value
5357 
5358   Output Parameter:
5359 . points - The stratum points, or NULL if the label does not exist or does not have that value
5360 
5361   Level: beginner
5362 
5363 .keywords: mesh
5364 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5365 @*/
5366 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5367 {
5368   DMLabel        label;
5369   PetscErrorCode ierr;
5370 
5371   PetscFunctionBegin;
5372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5373   PetscValidCharPointer(name, 2);
5374   PetscValidPointer(points, 4);
5375   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5376   *points = NULL;
5377   if (!label) PetscFunctionReturn(0);
5378   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5379   PetscFunctionReturn(0);
5380 }
5381 
5382 /*@C
5383   DMGetStratumIS - Set the points in a label stratum
5384 
5385   Not Collective
5386 
5387   Input Parameters:
5388 + dm - The DM object
5389 . name - The label name
5390 . value - The stratum value
5391 - points - The stratum points
5392 
5393   Level: beginner
5394 
5395 .keywords: mesh
5396 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5397 @*/
5398 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5399 {
5400   DMLabel        label;
5401   PetscErrorCode ierr;
5402 
5403   PetscFunctionBegin;
5404   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5405   PetscValidCharPointer(name, 2);
5406   PetscValidPointer(points, 4);
5407   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5408   if (!label) PetscFunctionReturn(0);
5409   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5410   PetscFunctionReturn(0);
5411 }
5412 
5413 /*@C
5414   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5415 
5416   Not Collective
5417 
5418   Input Parameters:
5419 + dm   - The DM object
5420 . name - The label name
5421 - value - The label value for this point
5422 
5423   Output Parameter:
5424 
5425   Level: beginner
5426 
5427 .keywords: mesh
5428 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5429 @*/
5430 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5431 {
5432   DMLabel        label;
5433   PetscErrorCode ierr;
5434 
5435   PetscFunctionBegin;
5436   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5437   PetscValidCharPointer(name, 2);
5438   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5439   if (!label) PetscFunctionReturn(0);
5440   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5441   PetscFunctionReturn(0);
5442 }
5443 
5444 /*@
5445   DMGetNumLabels - Return the number of labels defined by the mesh
5446 
5447   Not Collective
5448 
5449   Input Parameter:
5450 . dm   - The DM object
5451 
5452   Output Parameter:
5453 . numLabels - the number of Labels
5454 
5455   Level: intermediate
5456 
5457 .keywords: mesh
5458 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5459 @*/
5460 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5461 {
5462   DMLabelLink next = dm->labels->next;
5463   PetscInt  n    = 0;
5464 
5465   PetscFunctionBegin;
5466   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5467   PetscValidPointer(numLabels, 2);
5468   while (next) {++n; next = next->next;}
5469   *numLabels = n;
5470   PetscFunctionReturn(0);
5471 }
5472 
5473 /*@C
5474   DMGetLabelName - Return the name of nth label
5475 
5476   Not Collective
5477 
5478   Input Parameters:
5479 + dm - The DM object
5480 - n  - the label number
5481 
5482   Output Parameter:
5483 . name - the label name
5484 
5485   Level: intermediate
5486 
5487 .keywords: mesh
5488 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5489 @*/
5490 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5491 {
5492   DMLabelLink next = dm->labels->next;
5493   PetscInt  l    = 0;
5494 
5495   PetscFunctionBegin;
5496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5497   PetscValidPointer(name, 3);
5498   while (next) {
5499     if (l == n) {
5500       *name = next->label->name;
5501       PetscFunctionReturn(0);
5502     }
5503     ++l;
5504     next = next->next;
5505   }
5506   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5507 }
5508 
5509 /*@C
5510   DMHasLabel - Determine whether the mesh has a label of a given name
5511 
5512   Not Collective
5513 
5514   Input Parameters:
5515 + dm   - The DM object
5516 - name - The label name
5517 
5518   Output Parameter:
5519 . hasLabel - PETSC_TRUE if the label is present
5520 
5521   Level: intermediate
5522 
5523 .keywords: mesh
5524 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5525 @*/
5526 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5527 {
5528   DMLabelLink    next = dm->labels->next;
5529   PetscErrorCode ierr;
5530 
5531   PetscFunctionBegin;
5532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5533   PetscValidCharPointer(name, 2);
5534   PetscValidPointer(hasLabel, 3);
5535   *hasLabel = PETSC_FALSE;
5536   while (next) {
5537     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5538     if (*hasLabel) break;
5539     next = next->next;
5540   }
5541   PetscFunctionReturn(0);
5542 }
5543 
5544 /*@C
5545   DMGetLabel - Return the label of a given name, or NULL
5546 
5547   Not Collective
5548 
5549   Input Parameters:
5550 + dm   - The DM object
5551 - name - The label name
5552 
5553   Output Parameter:
5554 . label - The DMLabel, or NULL if the label is absent
5555 
5556   Level: intermediate
5557 
5558 .keywords: mesh
5559 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5560 @*/
5561 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5562 {
5563   DMLabelLink    next = dm->labels->next;
5564   PetscBool      hasLabel;
5565   PetscErrorCode ierr;
5566 
5567   PetscFunctionBegin;
5568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5569   PetscValidCharPointer(name, 2);
5570   PetscValidPointer(label, 3);
5571   *label = NULL;
5572   while (next) {
5573     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5574     if (hasLabel) {
5575       *label = next->label;
5576       break;
5577     }
5578     next = next->next;
5579   }
5580   PetscFunctionReturn(0);
5581 }
5582 
5583 /*@C
5584   DMGetLabelByNum - Return the nth label
5585 
5586   Not Collective
5587 
5588   Input Parameters:
5589 + dm - The DM object
5590 - n  - the label number
5591 
5592   Output Parameter:
5593 . label - the label
5594 
5595   Level: intermediate
5596 
5597 .keywords: mesh
5598 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5599 @*/
5600 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5601 {
5602   DMLabelLink next = dm->labels->next;
5603   PetscInt    l    = 0;
5604 
5605   PetscFunctionBegin;
5606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5607   PetscValidPointer(label, 3);
5608   while (next) {
5609     if (l == n) {
5610       *label = next->label;
5611       PetscFunctionReturn(0);
5612     }
5613     ++l;
5614     next = next->next;
5615   }
5616   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5617 }
5618 
5619 /*@C
5620   DMAddLabel - Add the label to this mesh
5621 
5622   Not Collective
5623 
5624   Input Parameters:
5625 + dm   - The DM object
5626 - label - The DMLabel
5627 
5628   Level: developer
5629 
5630 .keywords: mesh
5631 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5632 @*/
5633 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5634 {
5635   DMLabelLink    tmpLabel;
5636   PetscBool      hasLabel;
5637   PetscErrorCode ierr;
5638 
5639   PetscFunctionBegin;
5640   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5641   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5642   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5643   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5644   tmpLabel->label  = label;
5645   tmpLabel->output = PETSC_TRUE;
5646   tmpLabel->next   = dm->labels->next;
5647   dm->labels->next = tmpLabel;
5648   PetscFunctionReturn(0);
5649 }
5650 
5651 /*@C
5652   DMRemoveLabel - Remove the label from this mesh
5653 
5654   Not Collective
5655 
5656   Input Parameters:
5657 + dm   - The DM object
5658 - name - The label name
5659 
5660   Output Parameter:
5661 . label - The DMLabel, or NULL if the label is absent
5662 
5663   Level: developer
5664 
5665 .keywords: mesh
5666 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5667 @*/
5668 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5669 {
5670   DMLabelLink    next = dm->labels->next;
5671   DMLabelLink    last = NULL;
5672   PetscBool      hasLabel;
5673   PetscErrorCode ierr;
5674 
5675   PetscFunctionBegin;
5676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5677   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5678   *label = NULL;
5679   if (!hasLabel) PetscFunctionReturn(0);
5680   while (next) {
5681     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5682     if (hasLabel) {
5683       if (last) last->next       = next->next;
5684       else      dm->labels->next = next->next;
5685       next->next = NULL;
5686       *label     = next->label;
5687       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5688       if (hasLabel) {
5689         dm->depthLabel = NULL;
5690       }
5691       ierr = PetscFree(next);CHKERRQ(ierr);
5692       break;
5693     }
5694     last = next;
5695     next = next->next;
5696   }
5697   PetscFunctionReturn(0);
5698 }
5699 
5700 /*@C
5701   DMGetLabelOutput - Get the output flag for a given label
5702 
5703   Not Collective
5704 
5705   Input Parameters:
5706 + dm   - The DM object
5707 - name - The label name
5708 
5709   Output Parameter:
5710 . output - The flag for output
5711 
5712   Level: developer
5713 
5714 .keywords: mesh
5715 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5716 @*/
5717 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5718 {
5719   DMLabelLink    next = dm->labels->next;
5720   PetscErrorCode ierr;
5721 
5722   PetscFunctionBegin;
5723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5724   PetscValidPointer(name, 2);
5725   PetscValidPointer(output, 3);
5726   while (next) {
5727     PetscBool flg;
5728 
5729     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5730     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5731     next = next->next;
5732   }
5733   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5734 }
5735 
5736 /*@C
5737   DMSetLabelOutput - Set the output flag for a given label
5738 
5739   Not Collective
5740 
5741   Input Parameters:
5742 + dm     - The DM object
5743 . name   - The label name
5744 - output - The flag for output
5745 
5746   Level: developer
5747 
5748 .keywords: mesh
5749 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5750 @*/
5751 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5752 {
5753   DMLabelLink    next = dm->labels->next;
5754   PetscErrorCode ierr;
5755 
5756   PetscFunctionBegin;
5757   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5758   PetscValidPointer(name, 2);
5759   while (next) {
5760     PetscBool flg;
5761 
5762     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5763     if (flg) {next->output = output; PetscFunctionReturn(0);}
5764     next = next->next;
5765   }
5766   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5767 }
5768 
5769 
5770 /*@
5771   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5772 
5773   Collective on DM
5774 
5775   Input Parameter:
5776 . dmA - The DM object with initial labels
5777 
5778   Output Parameter:
5779 . dmB - The DM object with copied labels
5780 
5781   Level: intermediate
5782 
5783   Note: This is typically used when interpolating or otherwise adding to a mesh
5784 
5785 .keywords: mesh
5786 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5787 @*/
5788 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5789 {
5790   PetscInt       numLabels, l;
5791   PetscErrorCode ierr;
5792 
5793   PetscFunctionBegin;
5794   if (dmA == dmB) PetscFunctionReturn(0);
5795   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5796   for (l = 0; l < numLabels; ++l) {
5797     DMLabel     label, labelNew;
5798     const char *name;
5799     PetscBool   flg;
5800 
5801     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5802     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5803     if (flg) continue;
5804     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5805     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5806     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5807   }
5808   PetscFunctionReturn(0);
5809 }
5810 
5811 /*@
5812   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5813 
5814   Input Parameter:
5815 . dm - The DM object
5816 
5817   Output Parameter:
5818 . cdm - The coarse DM
5819 
5820   Level: intermediate
5821 
5822 .seealso: DMSetCoarseDM()
5823 @*/
5824 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5825 {
5826   PetscFunctionBegin;
5827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5828   PetscValidPointer(cdm, 2);
5829   *cdm = dm->coarseMesh;
5830   PetscFunctionReturn(0);
5831 }
5832 
5833 /*@
5834   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5835 
5836   Input Parameters:
5837 + dm - The DM object
5838 - cdm - The coarse DM
5839 
5840   Level: intermediate
5841 
5842 .seealso: DMGetCoarseDM()
5843 @*/
5844 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5845 {
5846   PetscErrorCode ierr;
5847 
5848   PetscFunctionBegin;
5849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5850   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5851   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5852   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
5853   dm->coarseMesh = cdm;
5854   PetscFunctionReturn(0);
5855 }
5856 
5857 /*@
5858   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
5859 
5860   Input Parameter:
5861 . dm - The DM object
5862 
5863   Output Parameter:
5864 . fdm - The fine DM
5865 
5866   Level: intermediate
5867 
5868 .seealso: DMSetFineDM()
5869 @*/
5870 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
5871 {
5872   PetscFunctionBegin;
5873   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5874   PetscValidPointer(fdm, 2);
5875   *fdm = dm->fineMesh;
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 /*@
5880   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
5881 
5882   Input Parameters:
5883 + dm - The DM object
5884 - fdm - The fine DM
5885 
5886   Level: intermediate
5887 
5888 .seealso: DMGetFineDM()
5889 @*/
5890 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
5891 {
5892   PetscErrorCode ierr;
5893 
5894   PetscFunctionBegin;
5895   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5896   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
5897   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
5898   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
5899   dm->fineMesh = fdm;
5900   PetscFunctionReturn(0);
5901 }
5902 
5903 /*=== DMBoundary code ===*/
5904 
5905 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
5906 {
5907   PetscErrorCode ierr;
5908 
5909   PetscFunctionBegin;
5910   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
5911   PetscFunctionReturn(0);
5912 }
5913 
5914 /*@C
5915   DMAddBoundary - Add a boundary condition to the model
5916 
5917   Input Parameters:
5918 + dm          - The DM, with a PetscDS that matches the problem being constrained
5919 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5920 . name        - The BC name
5921 . labelname   - The label defining constrained points
5922 . field       - The field to constrain
5923 . numcomps    - The number of constrained field components
5924 . comps       - An array of constrained component numbers
5925 . bcFunc      - A pointwise function giving boundary values
5926 . numids      - The number of DMLabel ids for constrained points
5927 . ids         - An array of ids for constrained points
5928 - ctx         - An optional user context for bcFunc
5929 
5930   Options Database Keys:
5931 + -bc_<boundary name> <num> - Overrides the boundary ids
5932 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5933 
5934   Level: developer
5935 
5936 .seealso: DMGetBoundary()
5937 @*/
5938 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)
5939 {
5940   PetscErrorCode ierr;
5941 
5942   PetscFunctionBegin;
5943   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5944   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
5945   PetscFunctionReturn(0);
5946 }
5947 
5948 /*@
5949   DMGetNumBoundary - Get the number of registered BC
5950 
5951   Input Parameters:
5952 . dm - The mesh object
5953 
5954   Output Parameters:
5955 . numBd - The number of BC
5956 
5957   Level: intermediate
5958 
5959 .seealso: DMAddBoundary(), DMGetBoundary()
5960 @*/
5961 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
5962 {
5963   PetscErrorCode ierr;
5964 
5965   PetscFunctionBegin;
5966   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5967   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
5968   PetscFunctionReturn(0);
5969 }
5970 
5971 /*@C
5972   DMGetBoundary - Get a model boundary condition
5973 
5974   Input Parameters:
5975 + dm          - The mesh object
5976 - bd          - The BC number
5977 
5978   Output Parameters:
5979 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5980 . name        - The BC name
5981 . labelname   - The label defining constrained points
5982 . field       - The field to constrain
5983 . numcomps    - The number of constrained field components
5984 . comps       - An array of constrained component numbers
5985 . bcFunc      - A pointwise function giving boundary values
5986 . numids      - The number of DMLabel ids for constrained points
5987 . ids         - An array of ids for constrained points
5988 - ctx         - An optional user context for bcFunc
5989 
5990   Options Database Keys:
5991 + -bc_<boundary name> <num> - Overrides the boundary ids
5992 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5993 
5994   Level: developer
5995 
5996 .seealso: DMAddBoundary()
5997 @*/
5998 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)
5999 {
6000   PetscErrorCode ierr;
6001 
6002   PetscFunctionBegin;
6003   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6004   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
6005   PetscFunctionReturn(0);
6006 }
6007 
6008 static PetscErrorCode DMPopulateBoundary(DM dm)
6009 {
6010   DMBoundary *lastnext;
6011   DSBoundary dsbound;
6012   PetscErrorCode ierr;
6013 
6014   PetscFunctionBegin;
6015   dsbound = dm->prob->boundary;
6016   if (dm->boundary) {
6017     DMBoundary next = dm->boundary;
6018 
6019     /* quick check to see if the PetscDS has changed */
6020     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
6021     /* the PetscDS has changed: tear down and rebuild */
6022     while (next) {
6023       DMBoundary b = next;
6024 
6025       next = b->next;
6026       ierr = PetscFree(b);CHKERRQ(ierr);
6027     }
6028     dm->boundary = NULL;
6029   }
6030 
6031   lastnext = &(dm->boundary);
6032   while (dsbound) {
6033     DMBoundary dmbound;
6034 
6035     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
6036     dmbound->dsboundary = dsbound;
6037     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
6038     if (!dmbound->label) PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);
6039     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6040     *lastnext = dmbound;
6041     lastnext = &(dmbound->next);
6042     dsbound = dsbound->next;
6043   }
6044   PetscFunctionReturn(0);
6045 }
6046 
6047 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6048 {
6049   DMBoundary     b;
6050   PetscErrorCode ierr;
6051 
6052   PetscFunctionBegin;
6053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6054   PetscValidPointer(isBd, 3);
6055   *isBd = PETSC_FALSE;
6056   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
6057   b = dm->boundary;
6058   while (b && !(*isBd)) {
6059     DMLabel    label = b->label;
6060     DSBoundary dsb = b->dsboundary;
6061 
6062     if (label) {
6063       PetscInt i;
6064 
6065       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6066         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
6067       }
6068     }
6069     b = b->next;
6070   }
6071   PetscFunctionReturn(0);
6072 }
6073 
6074 /*@C
6075   DMProjectFunction - This projects the given function into the function space provided.
6076 
6077   Input Parameters:
6078 + dm      - The DM
6079 . time    - The time
6080 . funcs   - The coordinate functions to evaluate, one per field
6081 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6082 - mode    - The insertion mode for values
6083 
6084   Output Parameter:
6085 . X - vector
6086 
6087    Calling sequence of func:
6088 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
6089 
6090 +  dim - The spatial dimension
6091 .  x   - The coordinates
6092 .  Nf  - The number of fields
6093 .  u   - The output field values
6094 -  ctx - optional user-defined function context
6095 
6096   Level: developer
6097 
6098 .seealso: DMComputeL2Diff()
6099 @*/
6100 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6101 {
6102   Vec            localX;
6103   PetscErrorCode ierr;
6104 
6105   PetscFunctionBegin;
6106   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6107   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6108   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6109   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6110   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6111   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6112   PetscFunctionReturn(0);
6113 }
6114 
6115 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6116 {
6117   PetscErrorCode ierr;
6118 
6119   PetscFunctionBegin;
6120   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6121   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6122   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6123   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6124   PetscFunctionReturn(0);
6125 }
6126 
6127 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)
6128 {
6129   Vec            localX;
6130   PetscErrorCode ierr;
6131 
6132   PetscFunctionBegin;
6133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6134   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6135   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6136   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6137   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6138   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6139   PetscFunctionReturn(0);
6140 }
6141 
6142 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)
6143 {
6144   PetscErrorCode ierr;
6145 
6146   PetscFunctionBegin;
6147   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6148   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6149   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6150   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6151   PetscFunctionReturn(0);
6152 }
6153 
6154 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6155                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6156                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6157                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6158                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6159                                    InsertMode mode, Vec localX)
6160 {
6161   PetscErrorCode ierr;
6162 
6163   PetscFunctionBegin;
6164   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6165   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
6166   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
6167   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6168   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
6169   PetscFunctionReturn(0);
6170 }
6171 
6172 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6173                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6174                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6175                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6176                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6177                                         InsertMode mode, Vec localX)
6178 {
6179   PetscErrorCode ierr;
6180 
6181   PetscFunctionBegin;
6182   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6183   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
6184   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
6185   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6186   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
6187   PetscFunctionReturn(0);
6188 }
6189 
6190 /*@C
6191   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
6192 
6193   Input Parameters:
6194 + dm    - The DM
6195 . time  - The time
6196 . funcs - The functions to evaluate for each field component
6197 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6198 - X     - The coefficient vector u_h, a global vector
6199 
6200   Output Parameter:
6201 . diff - The diff ||u - u_h||_2
6202 
6203   Level: developer
6204 
6205 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6206 @*/
6207 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6208 {
6209   PetscErrorCode ierr;
6210 
6211   PetscFunctionBegin;
6212   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6213   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6214   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6215   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6216   PetscFunctionReturn(0);
6217 }
6218 
6219 /*@C
6220   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
6221 
6222   Input Parameters:
6223 + dm    - The DM
6224 , time  - The time
6225 . funcs - The gradient functions to evaluate for each field component
6226 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6227 . X     - The coefficient vector u_h, a global vector
6228 - n     - The vector to project along
6229 
6230   Output Parameter:
6231 . diff - The diff ||(grad u - grad u_h) . n||_2
6232 
6233   Level: developer
6234 
6235 .seealso: DMProjectFunction(), DMComputeL2Diff()
6236 @*/
6237 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)
6238 {
6239   PetscErrorCode ierr;
6240 
6241   PetscFunctionBegin;
6242   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6243   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6244   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6245   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6246   PetscFunctionReturn(0);
6247 }
6248 
6249 /*@C
6250   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6251 
6252   Input Parameters:
6253 + dm    - The DM
6254 . time  - The time
6255 . funcs - The functions to evaluate for each field component
6256 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6257 - X     - The coefficient vector u_h, a global vector
6258 
6259   Output Parameter:
6260 . diff - The array of differences, ||u^f - u^f_h||_2
6261 
6262   Level: developer
6263 
6264 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6265 @*/
6266 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6267 {
6268   PetscErrorCode ierr;
6269 
6270   PetscFunctionBegin;
6271   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6272   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6273   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6274   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6275   PetscFunctionReturn(0);
6276 }
6277 
6278 /*@C
6279   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6280                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6281 
6282   Collective on dm
6283 
6284   Input parameters:
6285 + dm - the pre-adaptation DM object
6286 - label - label with the flags
6287 
6288   Output parameters:
6289 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
6290 
6291   Level: intermediate
6292 
6293 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6294 @*/
6295 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6296 {
6297   PetscErrorCode ierr;
6298 
6299   PetscFunctionBegin;
6300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6301   PetscValidPointer(label,2);
6302   PetscValidPointer(dmAdapt,3);
6303   *dmAdapt = NULL;
6304   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6305   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
6306   PetscFunctionReturn(0);
6307 }
6308 
6309 /*@C
6310   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
6311 
6312   Input Parameters:
6313 + dm - The DM object
6314 . metric - The metric to which the mesh is adapted, defined vertex-wise.
6315 - 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_".
6316 
6317   Output Parameter:
6318 . dmAdapt  - Pointer to the DM object containing the adapted mesh
6319 
6320   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
6321 
6322   Level: advanced
6323 
6324 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6325 @*/
6326 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6327 {
6328   PetscErrorCode ierr;
6329 
6330   PetscFunctionBegin;
6331   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6332   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
6333   if (bdLabel) PetscValidPointer(bdLabel, 3);
6334   PetscValidPointer(dmAdapt, 4);
6335   *dmAdapt = NULL;
6336   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6337   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
6338   PetscFunctionReturn(0);
6339 }
6340 
6341 /*@C
6342  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6343 
6344  Not Collective
6345 
6346  Input Parameter:
6347  . dm    - The DM
6348 
6349  Output Parameter:
6350  . nranks - the number of neighbours
6351  . ranks - the neighbors ranks
6352 
6353  Notes:
6354  Do not free the array, it is freed when the DM is destroyed.
6355 
6356  Level: beginner
6357 
6358  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6359 @*/
6360 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6361 {
6362   PetscErrorCode ierr;
6363 
6364   PetscFunctionBegin;
6365   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6366   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6367   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6368   PetscFunctionReturn(0);
6369 }
6370 
6371 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6372 
6373 /*
6374     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6375     This has be a different function because it requires DM which is not defined in the Mat library
6376 */
6377 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6378 {
6379   PetscErrorCode ierr;
6380 
6381   PetscFunctionBegin;
6382   if (coloring->ctype == IS_COLORING_LOCAL) {
6383     Vec x1local;
6384     DM  dm;
6385     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6386     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6387     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6388     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6389     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6390     x1   = x1local;
6391   }
6392   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6393   if (coloring->ctype == IS_COLORING_LOCAL) {
6394     DM  dm;
6395     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6396     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6397   }
6398   PetscFunctionReturn(0);
6399 }
6400 
6401 /*@
6402     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6403 
6404     Input Parameter:
6405 .    coloring - the MatFDColoring object
6406 
6407     Developer Notes: this routine exists because the PETSc Mat library does not know about the DM objects
6408 
6409     Level: advanced
6410 
6411 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6412 @*/
6413 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6414 {
6415   PetscFunctionBegin;
6416   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6417   PetscFunctionReturn(0);
6418 }
6419