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