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