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