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