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