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