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