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