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