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