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