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