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