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