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