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