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