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