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