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