xref: /petsc/src/dm/interface/dm.c (revision c06a8e02ff6b77f4014c18ceca68570eef2eedb9) !
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(), DMPlexCreateBasisRotation()
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.
6052 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
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   Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.
6057 
6058   Level: developer
6059 
6060 .seealso: DMGetPeriodicity()
6061 @*/
6062 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6063 {
6064   PetscInt       dim, d;
6065   PetscErrorCode ierr;
6066 
6067   PetscFunctionBegin;
6068   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6069   PetscValidLogicalCollectiveBool(dm,per,2);
6070   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6071   if (L)       {PetscValidRealPointer(L,4);}
6072   if (bd)      {PetscValidPointer(bd,5);}
6073   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6074   if (maxCell) {
6075     if (!dm->maxCell) {ierr = PetscMalloc1(dim, &dm->maxCell);CHKERRQ(ierr);}
6076     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6077   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6078     ierr = PetscFree(dm->maxCell);CHKERRQ(ierr);
6079   }
6080 
6081   if (L) {
6082     if (!dm->L) {ierr = PetscMalloc1(dim, &dm->L);CHKERRQ(ierr);}
6083     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6084   }
6085   if (bd) {
6086     if (!dm->bdtype) {ierr = PetscMalloc1(dim, &dm->bdtype);CHKERRQ(ierr);}
6087     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6088   }
6089   dm->periodic = per;
6090   PetscFunctionReturn(0);
6091 }
6092 
6093 /*@
6094   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.
6095 
6096   Input Parameters:
6097 + dm     - The DM
6098 . in     - The input coordinate point (dim numbers)
6099 - endpoint - Include the endpoint L_i
6100 
6101   Output Parameter:
6102 . out - The localized coordinate point
6103 
6104   Level: developer
6105 
6106 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6107 @*/
6108 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6109 {
6110   PetscInt       dim, d;
6111   PetscErrorCode ierr;
6112 
6113   PetscFunctionBegin;
6114   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
6115   if (!dm->maxCell) {
6116     for (d = 0; d < dim; ++d) out[d] = in[d];
6117   } else {
6118     if (endpoint) {
6119       for (d = 0; d < dim; ++d) {
6120         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)) {
6121           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6122         } else {
6123           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6124         }
6125       }
6126     } else {
6127       for (d = 0; d < dim; ++d) {
6128         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6129       }
6130     }
6131   }
6132   PetscFunctionReturn(0);
6133 }
6134 
6135 /*
6136   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.
6137 
6138   Input Parameters:
6139 + dm     - The DM
6140 . dim    - The spatial dimension
6141 . anchor - The anchor point, the input point can be no more than maxCell away from it
6142 - in     - The input coordinate point (dim numbers)
6143 
6144   Output Parameter:
6145 . out - The localized coordinate point
6146 
6147   Level: developer
6148 
6149   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell
6150 
6151 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6152 */
6153 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6154 {
6155   PetscInt d;
6156 
6157   PetscFunctionBegin;
6158   if (!dm->maxCell) {
6159     for (d = 0; d < dim; ++d) out[d] = in[d];
6160   } else {
6161     for (d = 0; d < dim; ++d) {
6162       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6163         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6164       } else {
6165         out[d] = in[d];
6166       }
6167     }
6168   }
6169   PetscFunctionReturn(0);
6170 }
6171 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6172 {
6173   PetscInt d;
6174 
6175   PetscFunctionBegin;
6176   if (!dm->maxCell) {
6177     for (d = 0; d < dim; ++d) out[d] = in[d];
6178   } else {
6179     for (d = 0; d < dim; ++d) {
6180       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6181         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6182       } else {
6183         out[d] = in[d];
6184       }
6185     }
6186   }
6187   PetscFunctionReturn(0);
6188 }
6189 
6190 /*
6191   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.
6192 
6193   Input Parameters:
6194 + dm     - The DM
6195 . dim    - The spatial dimension
6196 . anchor - The anchor point, the input point can be no more than maxCell away from it
6197 . in     - The input coordinate delta (dim numbers)
6198 - out    - The input coordinate point (dim numbers)
6199 
6200   Output Parameter:
6201 . out    - The localized coordinate in + out
6202 
6203   Level: developer
6204 
6205   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
6206 
6207 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6208 */
6209 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6210 {
6211   PetscInt d;
6212 
6213   PetscFunctionBegin;
6214   if (!dm->maxCell) {
6215     for (d = 0; d < dim; ++d) out[d] += in[d];
6216   } else {
6217     for (d = 0; d < dim; ++d) {
6218       const PetscReal maxC = dm->maxCell[d];
6219 
6220       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6221         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6222 
6223         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6224           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]));
6225         out[d] += newCoord;
6226       } else {
6227         out[d] += in[d];
6228       }
6229     }
6230   }
6231   PetscFunctionReturn(0);
6232 }
6233 
6234 /*@
6235   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6236 
6237   Not collective
6238 
6239   Input Parameter:
6240 . dm - The DM
6241 
6242   Output Parameter:
6243   areLocalized - True if localized
6244 
6245   Level: developer
6246 
6247 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6248 @*/
6249 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6250 {
6251   DM             cdm;
6252   PetscSection   coordSection;
6253   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6254   PetscBool      isPlex, alreadyLocalized;
6255   PetscErrorCode ierr;
6256 
6257   PetscFunctionBegin;
6258   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6259   PetscValidBoolPointer(areLocalized, 2);
6260   *areLocalized = PETSC_FALSE;
6261 
6262   /* We need some generic way of refering to cells/vertices */
6263   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6264   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6265   if (!isPlex) PetscFunctionReturn(0);
6266 
6267   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6268   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6269   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6270   alreadyLocalized = PETSC_FALSE;
6271   for (c = cStart; c < cEnd; ++c) {
6272     if (c < sStart || c >= sEnd) continue;
6273     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6274     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6275   }
6276   *areLocalized = alreadyLocalized;
6277   PetscFunctionReturn(0);
6278 }
6279 
6280 /*@
6281   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6282 
6283   Collective on dm
6284 
6285   Input Parameter:
6286 . dm - The DM
6287 
6288   Output Parameter:
6289   areLocalized - True if localized
6290 
6291   Level: developer
6292 
6293 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6294 @*/
6295 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6296 {
6297   PetscBool      localized;
6298   PetscErrorCode ierr;
6299 
6300   PetscFunctionBegin;
6301   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6302   PetscValidBoolPointer(areLocalized, 2);
6303   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6304   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6305   PetscFunctionReturn(0);
6306 }
6307 
6308 /*@
6309   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6310 
6311   Collective on dm
6312 
6313   Input Parameter:
6314 . dm - The DM
6315 
6316   Level: developer
6317 
6318 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6319 @*/
6320 PetscErrorCode DMLocalizeCoordinates(DM dm)
6321 {
6322   DM             cdm;
6323   PetscSection   coordSection, cSection;
6324   Vec            coordinates,  cVec;
6325   PetscScalar   *coords, *coords2, *anchor, *localized;
6326   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6327   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6328   PetscInt       maxHeight = 0, h;
6329   PetscInt       *pStart = NULL, *pEnd = NULL;
6330   PetscErrorCode ierr;
6331 
6332   PetscFunctionBegin;
6333   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6334   if (!dm->periodic) PetscFunctionReturn(0);
6335   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6336   if (alreadyLocalized) PetscFunctionReturn(0);
6337 
6338   /* We need some generic way of refering to cells/vertices */
6339   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6340   {
6341     PetscBool isplex;
6342 
6343     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6344     if (isplex) {
6345       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6346       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6347       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6348       pEnd = &pStart[maxHeight + 1];
6349       newStart = vStart;
6350       newEnd   = vEnd;
6351       for (h = 0; h <= maxHeight; h++) {
6352         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6353         newStart = PetscMin(newStart,pStart[h]);
6354         newEnd   = PetscMax(newEnd,pEnd[h]);
6355       }
6356     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6357   }
6358   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6359   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6360   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6361   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6362   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6363 
6364   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6365   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6366   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6367   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6368   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6369 
6370   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6371   localized = &anchor[bs];
6372   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6373   for (h = 0; h <= maxHeight; h++) {
6374     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6375 
6376     for (c = cStart; c < cEnd; ++c) {
6377       PetscScalar *cellCoords = NULL;
6378       PetscInt     b;
6379 
6380       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6381       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6382       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6383       for (d = 0; d < dof/bs; ++d) {
6384         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6385         for (b = 0; b < bs; b++) {
6386           if (cellCoords[d*bs + b] != localized[b]) break;
6387         }
6388         if (b < bs) break;
6389       }
6390       if (d < dof/bs) {
6391         if (c >= sStart && c < sEnd) {
6392           PetscInt cdof;
6393 
6394           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6395           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6396         }
6397         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6398         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6399       }
6400       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6401     }
6402   }
6403   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6404   if (alreadyLocalizedGlobal) {
6405     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6406     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6407     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6408     PetscFunctionReturn(0);
6409   }
6410   for (v = vStart; v < vEnd; ++v) {
6411     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6412     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6413     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6414   }
6415   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6416   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6417   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6418   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6419   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6420   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6421   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6422   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6423   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6424   for (v = vStart; v < vEnd; ++v) {
6425     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6426     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6427     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6428     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6429   }
6430   for (h = 0; h <= maxHeight; h++) {
6431     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6432 
6433     for (c = cStart; c < cEnd; ++c) {
6434       PetscScalar *cellCoords = NULL;
6435       PetscInt     b, cdof;
6436 
6437       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6438       if (!cdof) continue;
6439       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6440       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6441       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6442       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6443       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6444     }
6445   }
6446   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6447   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6448   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6449   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6450   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6451   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6452   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6453   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6454   PetscFunctionReturn(0);
6455 }
6456 
6457 /*@
6458   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6459 
6460   Collective on v (see explanation below)
6461 
6462   Input Parameters:
6463 + dm - The DM
6464 . v - The Vec of points
6465 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6466 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6467 
6468   Output Parameter:
6469 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6470 - cells - The PetscSF containing the ranks and local indices of the containing points.
6471 
6472 
6473   Level: developer
6474 
6475   Notes:
6476   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6477   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6478 
6479   If *cellSF is NULL on input, a PetscSF will be created.
6480   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6481 
6482   An array that maps each point to its containing cell can be obtained with
6483 
6484 $    const PetscSFNode *cells;
6485 $    PetscInt           nFound;
6486 $    const PetscInt    *found;
6487 $
6488 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6489 
6490   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6491   the index of the cell in its rank's local numbering.
6492 
6493 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6494 @*/
6495 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6496 {
6497   PetscErrorCode ierr;
6498 
6499   PetscFunctionBegin;
6500   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6501   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6502   PetscValidPointer(cellSF,4);
6503   if (*cellSF) {
6504     PetscMPIInt result;
6505 
6506     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6507     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6508     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6509   } else {
6510     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6511   }
6512   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6513   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6514   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6515   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6516   PetscFunctionReturn(0);
6517 }
6518 
6519 /*@
6520   DMGetOutputDM - Retrieve the DM associated with the layout for output
6521 
6522   Collective on dm
6523 
6524   Input Parameter:
6525 . dm - The original DM
6526 
6527   Output Parameter:
6528 . odm - The DM which provides the layout for output
6529 
6530   Level: intermediate
6531 
6532 .seealso: VecView(), DMGetGlobalSection()
6533 @*/
6534 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6535 {
6536   PetscSection   section;
6537   PetscBool      hasConstraints, ghasConstraints;
6538   PetscErrorCode ierr;
6539 
6540   PetscFunctionBegin;
6541   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6542   PetscValidPointer(odm,2);
6543   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6544   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6545   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6546   if (!ghasConstraints) {
6547     *odm = dm;
6548     PetscFunctionReturn(0);
6549   }
6550   if (!dm->dmBC) {
6551     PetscSection newSection, gsection;
6552     PetscSF      sf;
6553 
6554     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6555     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6556     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6557     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6558     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6559     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6560     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6561     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6562     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6563   }
6564   *odm = dm->dmBC;
6565   PetscFunctionReturn(0);
6566 }
6567 
6568 /*@
6569   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6570 
6571   Input Parameter:
6572 . dm - The original DM
6573 
6574   Output Parameters:
6575 + num - The output sequence number
6576 - val - The output sequence value
6577 
6578   Level: intermediate
6579 
6580   Note: This is intended for output that should appear in sequence, for instance
6581   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6582 
6583 .seealso: VecView()
6584 @*/
6585 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6586 {
6587   PetscFunctionBegin;
6588   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6589   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
6590   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
6591   PetscFunctionReturn(0);
6592 }
6593 
6594 /*@
6595   DMSetOutputSequenceNumber - Set the sequence number/value for output
6596 
6597   Input Parameters:
6598 + dm - The original DM
6599 . num - The output sequence number
6600 - val - The output sequence value
6601 
6602   Level: intermediate
6603 
6604   Note: This is intended for output that should appear in sequence, for instance
6605   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6606 
6607 .seealso: VecView()
6608 @*/
6609 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6610 {
6611   PetscFunctionBegin;
6612   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6613   dm->outputSequenceNum = num;
6614   dm->outputSequenceVal = val;
6615   PetscFunctionReturn(0);
6616 }
6617 
6618 /*@C
6619   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6620 
6621   Input Parameters:
6622 + dm   - The original DM
6623 . name - The sequence name
6624 - num  - The output sequence number
6625 
6626   Output Parameter:
6627 . val  - The output sequence value
6628 
6629   Level: intermediate
6630 
6631   Note: This is intended for output that should appear in sequence, for instance
6632   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6633 
6634 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6635 @*/
6636 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6637 {
6638   PetscBool      ishdf5;
6639   PetscErrorCode ierr;
6640 
6641   PetscFunctionBegin;
6642   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6643   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6644   PetscValidRealPointer(val,4);
6645   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6646   if (ishdf5) {
6647 #if defined(PETSC_HAVE_HDF5)
6648     PetscScalar value;
6649 
6650     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6651     *val = PetscRealPart(value);
6652 #endif
6653   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6654   PetscFunctionReturn(0);
6655 }
6656 
6657 /*@
6658   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6659 
6660   Not collective
6661 
6662   Input Parameter:
6663 . dm - The DM
6664 
6665   Output Parameter:
6666 . useNatural - The flag to build the mapping to a natural order during distribution
6667 
6668   Level: beginner
6669 
6670 .seealso: DMSetUseNatural(), DMCreate()
6671 @*/
6672 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6673 {
6674   PetscFunctionBegin;
6675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6676   PetscValidBoolPointer(useNatural, 2);
6677   *useNatural = dm->useNatural;
6678   PetscFunctionReturn(0);
6679 }
6680 
6681 /*@
6682   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6683 
6684   Collective on dm
6685 
6686   Input Parameters:
6687 + dm - The DM
6688 - useNatural - The flag to build the mapping to a natural order during distribution
6689 
6690   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6691 
6692   Level: beginner
6693 
6694 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6695 @*/
6696 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6697 {
6698   PetscFunctionBegin;
6699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6700   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6701   dm->useNatural = useNatural;
6702   PetscFunctionReturn(0);
6703 }
6704 
6705 
6706 /*@C
6707   DMCreateLabel - Create a label of the given name if it does not already exist
6708 
6709   Not Collective
6710 
6711   Input Parameters:
6712 + dm   - The DM object
6713 - name - The label name
6714 
6715   Level: intermediate
6716 
6717 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6718 @*/
6719 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6720 {
6721   PetscBool      flg;
6722   DMLabel        label;
6723   PetscErrorCode ierr;
6724 
6725   PetscFunctionBegin;
6726   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6727   PetscValidCharPointer(name, 2);
6728   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
6729   if (!flg) {
6730     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
6731     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
6732     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
6733   }
6734   PetscFunctionReturn(0);
6735 }
6736 
6737 /*@C
6738   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6739 
6740   Not Collective
6741 
6742   Input Parameters:
6743 + dm   - The DM object
6744 . name - The label name
6745 - point - The mesh point
6746 
6747   Output Parameter:
6748 . value - The label value for this point, or -1 if the point is not in the label
6749 
6750   Level: beginner
6751 
6752 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6753 @*/
6754 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6755 {
6756   DMLabel        label;
6757   PetscErrorCode ierr;
6758 
6759   PetscFunctionBegin;
6760   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6761   PetscValidCharPointer(name, 2);
6762   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6763   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6764   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6765   PetscFunctionReturn(0);
6766 }
6767 
6768 /*@C
6769   DMSetLabelValue - Add a point to a Sieve Label with given value
6770 
6771   Not Collective
6772 
6773   Input Parameters:
6774 + dm   - The DM object
6775 . name - The label name
6776 . point - The mesh point
6777 - value - The label value for this point
6778 
6779   Output Parameter:
6780 
6781   Level: beginner
6782 
6783 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6784 @*/
6785 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6786 {
6787   DMLabel        label;
6788   PetscErrorCode ierr;
6789 
6790   PetscFunctionBegin;
6791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6792   PetscValidCharPointer(name, 2);
6793   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6794   if (!label) {
6795     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6796     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6797   }
6798   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6799   PetscFunctionReturn(0);
6800 }
6801 
6802 /*@C
6803   DMClearLabelValue - Remove a point from a Sieve Label with given value
6804 
6805   Not Collective
6806 
6807   Input Parameters:
6808 + dm   - The DM object
6809 . name - The label name
6810 . point - The mesh point
6811 - value - The label value for this point
6812 
6813   Output Parameter:
6814 
6815   Level: beginner
6816 
6817 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6818 @*/
6819 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6820 {
6821   DMLabel        label;
6822   PetscErrorCode ierr;
6823 
6824   PetscFunctionBegin;
6825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6826   PetscValidCharPointer(name, 2);
6827   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6828   if (!label) PetscFunctionReturn(0);
6829   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6830   PetscFunctionReturn(0);
6831 }
6832 
6833 /*@C
6834   DMGetLabelSize - Get the number of different integer ids in a Label
6835 
6836   Not Collective
6837 
6838   Input Parameters:
6839 + dm   - The DM object
6840 - name - The label name
6841 
6842   Output Parameter:
6843 . size - The number of different integer ids, or 0 if the label does not exist
6844 
6845   Level: beginner
6846 
6847 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6848 @*/
6849 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6850 {
6851   DMLabel        label;
6852   PetscErrorCode ierr;
6853 
6854   PetscFunctionBegin;
6855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6856   PetscValidCharPointer(name, 2);
6857   PetscValidIntPointer(size, 3);
6858   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6859   *size = 0;
6860   if (!label) PetscFunctionReturn(0);
6861   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
6862   PetscFunctionReturn(0);
6863 }
6864 
6865 /*@C
6866   DMGetLabelIdIS - Get the integer ids in a label
6867 
6868   Not Collective
6869 
6870   Input Parameters:
6871 + mesh - The DM object
6872 - name - The label name
6873 
6874   Output Parameter:
6875 . ids - The integer ids, or NULL if the label does not exist
6876 
6877   Level: beginner
6878 
6879 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6880 @*/
6881 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6882 {
6883   DMLabel        label;
6884   PetscErrorCode ierr;
6885 
6886   PetscFunctionBegin;
6887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6888   PetscValidCharPointer(name, 2);
6889   PetscValidPointer(ids, 3);
6890   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6891   *ids = NULL;
6892  if (label) {
6893     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
6894   } else {
6895     /* returning an empty IS */
6896     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
6897   }
6898   PetscFunctionReturn(0);
6899 }
6900 
6901 /*@C
6902   DMGetStratumSize - Get the number of points in a label stratum
6903 
6904   Not Collective
6905 
6906   Input Parameters:
6907 + dm - The DM object
6908 . name - The label name
6909 - value - The stratum value
6910 
6911   Output Parameter:
6912 . size - The stratum size
6913 
6914   Level: beginner
6915 
6916 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6917 @*/
6918 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6919 {
6920   DMLabel        label;
6921   PetscErrorCode ierr;
6922 
6923   PetscFunctionBegin;
6924   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6925   PetscValidCharPointer(name, 2);
6926   PetscValidIntPointer(size, 4);
6927   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6928   *size = 0;
6929   if (!label) PetscFunctionReturn(0);
6930   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
6931   PetscFunctionReturn(0);
6932 }
6933 
6934 /*@C
6935   DMGetStratumIS - Get the points in a label stratum
6936 
6937   Not Collective
6938 
6939   Input Parameters:
6940 + dm - The DM object
6941 . name - The label name
6942 - value - The stratum value
6943 
6944   Output Parameter:
6945 . points - The stratum points, or NULL if the label does not exist or does not have that value
6946 
6947   Level: beginner
6948 
6949 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6950 @*/
6951 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6952 {
6953   DMLabel        label;
6954   PetscErrorCode ierr;
6955 
6956   PetscFunctionBegin;
6957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6958   PetscValidCharPointer(name, 2);
6959   PetscValidPointer(points, 4);
6960   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6961   *points = NULL;
6962   if (!label) PetscFunctionReturn(0);
6963   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
6964   PetscFunctionReturn(0);
6965 }
6966 
6967 /*@C
6968   DMSetStratumIS - Set the points in a label stratum
6969 
6970   Not Collective
6971 
6972   Input Parameters:
6973 + dm - The DM object
6974 . name - The label name
6975 . value - The stratum value
6976 - points - The stratum points
6977 
6978   Level: beginner
6979 
6980 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6981 @*/
6982 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6983 {
6984   DMLabel        label;
6985   PetscErrorCode ierr;
6986 
6987   PetscFunctionBegin;
6988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6989   PetscValidCharPointer(name, 2);
6990   PetscValidPointer(points, 4);
6991   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6992   if (!label) PetscFunctionReturn(0);
6993   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
6994   PetscFunctionReturn(0);
6995 }
6996 
6997 /*@C
6998   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
6999 
7000   Not Collective
7001 
7002   Input Parameters:
7003 + dm   - The DM object
7004 . name - The label name
7005 - value - The label value for this point
7006 
7007   Output Parameter:
7008 
7009   Level: beginner
7010 
7011 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7012 @*/
7013 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7014 {
7015   DMLabel        label;
7016   PetscErrorCode ierr;
7017 
7018   PetscFunctionBegin;
7019   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7020   PetscValidCharPointer(name, 2);
7021   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7022   if (!label) PetscFunctionReturn(0);
7023   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
7024   PetscFunctionReturn(0);
7025 }
7026 
7027 /*@
7028   DMGetNumLabels - Return the number of labels defined by the mesh
7029 
7030   Not Collective
7031 
7032   Input Parameter:
7033 . dm   - The DM object
7034 
7035   Output Parameter:
7036 . numLabels - the number of Labels
7037 
7038   Level: intermediate
7039 
7040 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7041 @*/
7042 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7043 {
7044   DMLabelLink next = dm->labels;
7045   PetscInt  n    = 0;
7046 
7047   PetscFunctionBegin;
7048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7049   PetscValidIntPointer(numLabels, 2);
7050   while (next) {++n; next = next->next;}
7051   *numLabels = n;
7052   PetscFunctionReturn(0);
7053 }
7054 
7055 /*@C
7056   DMGetLabelName - Return the name of nth label
7057 
7058   Not Collective
7059 
7060   Input Parameters:
7061 + dm - The DM object
7062 - n  - the label number
7063 
7064   Output Parameter:
7065 . name - the label name
7066 
7067   Level: intermediate
7068 
7069 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7070 @*/
7071 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7072 {
7073   DMLabelLink    next = dm->labels;
7074   PetscInt       l    = 0;
7075   PetscErrorCode ierr;
7076 
7077   PetscFunctionBegin;
7078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7079   PetscValidPointer(name, 3);
7080   while (next) {
7081     if (l == n) {
7082       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
7083       PetscFunctionReturn(0);
7084     }
7085     ++l;
7086     next = next->next;
7087   }
7088   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7089 }
7090 
7091 /*@C
7092   DMHasLabel - Determine whether the mesh has a label of a given name
7093 
7094   Not Collective
7095 
7096   Input Parameters:
7097 + dm   - The DM object
7098 - name - The label name
7099 
7100   Output Parameter:
7101 . hasLabel - PETSC_TRUE if the label is present
7102 
7103   Level: intermediate
7104 
7105 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7106 @*/
7107 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7108 {
7109   DMLabelLink    next = dm->labels;
7110   const char    *lname;
7111   PetscErrorCode ierr;
7112 
7113   PetscFunctionBegin;
7114   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7115   PetscValidCharPointer(name, 2);
7116   PetscValidBoolPointer(hasLabel, 3);
7117   *hasLabel = PETSC_FALSE;
7118   while (next) {
7119     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7120     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
7121     if (*hasLabel) break;
7122     next = next->next;
7123   }
7124   PetscFunctionReturn(0);
7125 }
7126 
7127 /*@C
7128   DMGetLabel - Return the label of a given name, or NULL
7129 
7130   Not Collective
7131 
7132   Input Parameters:
7133 + dm   - The DM object
7134 - name - The label name
7135 
7136   Output Parameter:
7137 . label - The DMLabel, or NULL if the label is absent
7138 
7139   Level: intermediate
7140 
7141 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7142 @*/
7143 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7144 {
7145   DMLabelLink    next = dm->labels;
7146   PetscBool      hasLabel;
7147   const char    *lname;
7148   PetscErrorCode ierr;
7149 
7150   PetscFunctionBegin;
7151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7152   PetscValidCharPointer(name, 2);
7153   PetscValidPointer(label, 3);
7154   *label = NULL;
7155   while (next) {
7156     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7157     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7158     if (hasLabel) {
7159       *label = next->label;
7160       break;
7161     }
7162     next = next->next;
7163   }
7164   PetscFunctionReturn(0);
7165 }
7166 
7167 /*@C
7168   DMGetLabelByNum - Return the nth label
7169 
7170   Not Collective
7171 
7172   Input Parameters:
7173 + dm - The DM object
7174 - n  - the label number
7175 
7176   Output Parameter:
7177 . label - the label
7178 
7179   Level: intermediate
7180 
7181 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7182 @*/
7183 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7184 {
7185   DMLabelLink next = dm->labels;
7186   PetscInt    l    = 0;
7187 
7188   PetscFunctionBegin;
7189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7190   PetscValidPointer(label, 3);
7191   while (next) {
7192     if (l == n) {
7193       *label = next->label;
7194       PetscFunctionReturn(0);
7195     }
7196     ++l;
7197     next = next->next;
7198   }
7199   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7200 }
7201 
7202 /*@C
7203   DMAddLabel - Add the label to this mesh
7204 
7205   Not Collective
7206 
7207   Input Parameters:
7208 + dm   - The DM object
7209 - label - The DMLabel
7210 
7211   Level: developer
7212 
7213 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7214 @*/
7215 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7216 {
7217   DMLabelLink    l, *p, tmpLabel;
7218   PetscBool      hasLabel;
7219   const char    *lname;
7220   PetscBool      flg;
7221   PetscErrorCode ierr;
7222 
7223   PetscFunctionBegin;
7224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7225   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7226   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7227   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7228   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7229   tmpLabel->label  = label;
7230   tmpLabel->output = PETSC_TRUE;
7231   for (p=&dm->labels; (l=*p); p=&l->next) {}
7232   *p = tmpLabel;
7233   ierr = PetscObjectReference((PetscObject)label);CHKERRQ(ierr);
7234   ierr = PetscStrcmp(lname, "depth", &flg);CHKERRQ(ierr);
7235   if (flg) dm->depthLabel = label;
7236   ierr = PetscStrcmp(lname, "celltype", &flg);CHKERRQ(ierr);
7237   if (flg) dm->celltypeLabel = label;
7238   PetscFunctionReturn(0);
7239 }
7240 
7241 /*@C
7242   DMRemoveLabel - Remove the label given by name from this mesh
7243 
7244   Not Collective
7245 
7246   Input Parameters:
7247 + dm   - The DM object
7248 - name - The label name
7249 
7250   Output Parameter:
7251 . label - The DMLabel, or NULL if the label is absent
7252 
7253   Level: developer
7254 
7255   Notes:
7256   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7257   DMLabelDestroy() on the label.
7258 
7259   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7260   call DMLabelDestroy(). Instead, the label is returned and the user is
7261   responsible of calling DMLabelDestroy() at some point.
7262 
7263 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7264 @*/
7265 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7266 {
7267   DMLabelLink    link, *pnext;
7268   PetscBool      hasLabel;
7269   const char    *lname;
7270   PetscErrorCode ierr;
7271 
7272   PetscFunctionBegin;
7273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7274   PetscValidCharPointer(name, 2);
7275   if (label) {
7276     PetscValidPointer(label, 3);
7277     *label = NULL;
7278   }
7279   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7280     ierr = PetscObjectGetName((PetscObject) link->label, &lname);CHKERRQ(ierr);
7281     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7282     if (hasLabel) {
7283       *pnext = link->next; /* Remove from list */
7284       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7285       if (hasLabel) dm->depthLabel = NULL;
7286       ierr = PetscStrcmp(name, "celltype", &hasLabel);CHKERRQ(ierr);
7287       if (hasLabel) dm->celltypeLabel = NULL;
7288       if (label) *label = link->label;
7289       else       {ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);}
7290       ierr = PetscFree(link);CHKERRQ(ierr);
7291       break;
7292     }
7293   }
7294   PetscFunctionReturn(0);
7295 }
7296 
7297 /*@
7298   DMRemoveLabelBySelf - Remove the label from this mesh
7299 
7300   Not Collective
7301 
7302   Input Parameters:
7303 + dm   - The DM object
7304 . label - (Optional) The DMLabel to be removed from the DM
7305 - failNotFound - Should it fail if the label is not found in the DM?
7306 
7307   Level: developer
7308 
7309   Notes:
7310   Only exactly the same instance is removed if found, name match is ignored.
7311   If the DM has an exclusive reference to the label, it gets destroyed and
7312   *label nullified.
7313 
7314 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7315 @*/
7316 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7317 {
7318   DMLabelLink    link, *pnext;
7319   PetscBool      hasLabel = PETSC_FALSE;
7320   PetscErrorCode ierr;
7321 
7322   PetscFunctionBegin;
7323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7324   PetscValidPointer(label, 2);
7325   if (!*label && !failNotFound) PetscFunctionReturn(0);
7326   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7327   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
7328   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7329     if (*label == link->label) {
7330       hasLabel = PETSC_TRUE;
7331       *pnext = link->next; /* Remove from list */
7332       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7333       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7334       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7335       ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);
7336       ierr = PetscFree(link);CHKERRQ(ierr);
7337       break;
7338     }
7339   }
7340   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7341   PetscFunctionReturn(0);
7342 }
7343 
7344 /*@C
7345   DMGetLabelOutput - Get the output flag for a given label
7346 
7347   Not Collective
7348 
7349   Input Parameters:
7350 + dm   - The DM object
7351 - name - The label name
7352 
7353   Output Parameter:
7354 . output - The flag for output
7355 
7356   Level: developer
7357 
7358 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7359 @*/
7360 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7361 {
7362   DMLabelLink    next = dm->labels;
7363   const char    *lname;
7364   PetscErrorCode ierr;
7365 
7366   PetscFunctionBegin;
7367   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7368   PetscValidPointer(name, 2);
7369   PetscValidPointer(output, 3);
7370   while (next) {
7371     PetscBool flg;
7372 
7373     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7374     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7375     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7376     next = next->next;
7377   }
7378   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7379 }
7380 
7381 /*@C
7382   DMSetLabelOutput - Set the output flag for a given label
7383 
7384   Not Collective
7385 
7386   Input Parameters:
7387 + dm     - The DM object
7388 . name   - The label name
7389 - output - The flag for output
7390 
7391   Level: developer
7392 
7393 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7394 @*/
7395 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7396 {
7397   DMLabelLink    next = dm->labels;
7398   const char    *lname;
7399   PetscErrorCode ierr;
7400 
7401   PetscFunctionBegin;
7402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7403   PetscValidCharPointer(name, 2);
7404   while (next) {
7405     PetscBool flg;
7406 
7407     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7408     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7409     if (flg) {next->output = output; PetscFunctionReturn(0);}
7410     next = next->next;
7411   }
7412   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7413 }
7414 
7415 /*@
7416   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7417 
7418   Collective on dmA
7419 
7420   Input Parameter:
7421 + dmA - The DM object with initial labels
7422 . dmB - The DM object with copied labels
7423 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7424 - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7425 
7426   Level: intermediate
7427 
7428   Note: This is typically used when interpolating or otherwise adding to a mesh
7429 
7430 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7431 @*/
7432 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7433 {
7434   DMLabel        label, labelNew;
7435   const char    *name;
7436   PetscBool      flg;
7437   DMLabelLink    link;
7438   PetscErrorCode ierr;
7439 
7440   PetscFunctionBegin;
7441   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7442   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7443   PetscValidLogicalCollectiveEnum(dmA, mode,3);
7444   PetscValidLogicalCollectiveBool(dmA, all, 4);
7445   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7446   if (dmA == dmB) PetscFunctionReturn(0);
7447   for (link=dmA->labels; link; link=link->next) {
7448     label=link->label;
7449     ierr = PetscObjectGetName((PetscObject)label, &name);CHKERRQ(ierr);
7450     if (!all) {
7451       ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7452       if (flg) continue;
7453       ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7454       if (flg) continue;
7455       ierr = PetscStrcmp(name, "celltype", &flg);CHKERRQ(ierr);
7456       if (flg) continue;
7457     }
7458     if (mode==PETSC_COPY_VALUES) {
7459       ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7460     } else {
7461       labelNew = label;
7462     }
7463     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7464     if (mode==PETSC_COPY_VALUES) {ierr = DMLabelDestroy(&labelNew);CHKERRQ(ierr);}
7465   }
7466   PetscFunctionReturn(0);
7467 }
7468 
7469 /*@
7470   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7471 
7472   Input Parameter:
7473 . dm - The DM object
7474 
7475   Output Parameter:
7476 . cdm - The coarse DM
7477 
7478   Level: intermediate
7479 
7480 .seealso: DMSetCoarseDM()
7481 @*/
7482 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7483 {
7484   PetscFunctionBegin;
7485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7486   PetscValidPointer(cdm, 2);
7487   *cdm = dm->coarseMesh;
7488   PetscFunctionReturn(0);
7489 }
7490 
7491 /*@
7492   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7493 
7494   Input Parameters:
7495 + dm - The DM object
7496 - cdm - The coarse DM
7497 
7498   Level: intermediate
7499 
7500 .seealso: DMGetCoarseDM()
7501 @*/
7502 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7503 {
7504   PetscErrorCode ierr;
7505 
7506   PetscFunctionBegin;
7507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7508   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7509   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7510   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7511   dm->coarseMesh = cdm;
7512   PetscFunctionReturn(0);
7513 }
7514 
7515 /*@
7516   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7517 
7518   Input Parameter:
7519 . dm - The DM object
7520 
7521   Output Parameter:
7522 . fdm - The fine DM
7523 
7524   Level: intermediate
7525 
7526 .seealso: DMSetFineDM()
7527 @*/
7528 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7529 {
7530   PetscFunctionBegin;
7531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7532   PetscValidPointer(fdm, 2);
7533   *fdm = dm->fineMesh;
7534   PetscFunctionReturn(0);
7535 }
7536 
7537 /*@
7538   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7539 
7540   Input Parameters:
7541 + dm - The DM object
7542 - fdm - The fine DM
7543 
7544   Level: intermediate
7545 
7546 .seealso: DMGetFineDM()
7547 @*/
7548 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7549 {
7550   PetscErrorCode ierr;
7551 
7552   PetscFunctionBegin;
7553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7554   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7555   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7556   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7557   dm->fineMesh = fdm;
7558   PetscFunctionReturn(0);
7559 }
7560 
7561 /*=== DMBoundary code ===*/
7562 
7563 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7564 {
7565   PetscInt       d;
7566   PetscErrorCode ierr;
7567 
7568   PetscFunctionBegin;
7569   for (d = 0; d < dm->Nds; ++d) {
7570     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7571   }
7572   PetscFunctionReturn(0);
7573 }
7574 
7575 /*@C
7576   DMAddBoundary - Add a boundary condition to the model
7577 
7578   Input Parameters:
7579 + dm          - The DM, with a PetscDS that matches the problem being constrained
7580 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7581 . name        - The BC name
7582 . labelname   - The label defining constrained points
7583 . field       - The field to constrain
7584 . numcomps    - The number of constrained field components (0 will constrain all fields)
7585 . comps       - An array of constrained component numbers
7586 . bcFunc      - A pointwise function giving boundary values
7587 . numids      - The number of DMLabel ids for constrained points
7588 . ids         - An array of ids for constrained points
7589 - ctx         - An optional user context for bcFunc
7590 
7591   Options Database Keys:
7592 + -bc_<boundary name> <num> - Overrides the boundary ids
7593 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7594 
7595   Level: developer
7596 
7597 .seealso: DMGetBoundary()
7598 @*/
7599 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)
7600 {
7601   PetscDS        ds;
7602   PetscErrorCode ierr;
7603 
7604   PetscFunctionBegin;
7605   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7606   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7607   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7608   PetscFunctionReturn(0);
7609 }
7610 
7611 /*@
7612   DMGetNumBoundary - Get the number of registered BC
7613 
7614   Input Parameters:
7615 . dm - The mesh object
7616 
7617   Output Parameters:
7618 . numBd - The number of BC
7619 
7620   Level: intermediate
7621 
7622 .seealso: DMAddBoundary(), DMGetBoundary()
7623 @*/
7624 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7625 {
7626   PetscDS        ds;
7627   PetscErrorCode ierr;
7628 
7629   PetscFunctionBegin;
7630   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7631   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7632   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7633   PetscFunctionReturn(0);
7634 }
7635 
7636 /*@C
7637   DMGetBoundary - Get a model boundary condition
7638 
7639   Input Parameters:
7640 + dm          - The mesh object
7641 - bd          - The BC number
7642 
7643   Output Parameters:
7644 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7645 . name        - The BC name
7646 . labelname   - The label defining constrained points
7647 . field       - The field to constrain
7648 . numcomps    - The number of constrained field components
7649 . comps       - An array of constrained component numbers
7650 . bcFunc      - A pointwise function giving boundary values
7651 . numids      - The number of DMLabel ids for constrained points
7652 . ids         - An array of ids for constrained points
7653 - ctx         - An optional user context for bcFunc
7654 
7655   Options Database Keys:
7656 + -bc_<boundary name> <num> - Overrides the boundary ids
7657 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7658 
7659   Level: developer
7660 
7661 .seealso: DMAddBoundary()
7662 @*/
7663 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)
7664 {
7665   PetscDS        ds;
7666   PetscErrorCode ierr;
7667 
7668   PetscFunctionBegin;
7669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7670   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7671   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7672   PetscFunctionReturn(0);
7673 }
7674 
7675 static PetscErrorCode DMPopulateBoundary(DM dm)
7676 {
7677   PetscDS        ds;
7678   DMBoundary    *lastnext;
7679   DSBoundary     dsbound;
7680   PetscErrorCode ierr;
7681 
7682   PetscFunctionBegin;
7683   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7684   dsbound = ds->boundary;
7685   if (dm->boundary) {
7686     DMBoundary next = dm->boundary;
7687 
7688     /* quick check to see if the PetscDS has changed */
7689     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7690     /* the PetscDS has changed: tear down and rebuild */
7691     while (next) {
7692       DMBoundary b = next;
7693 
7694       next = b->next;
7695       ierr = PetscFree(b);CHKERRQ(ierr);
7696     }
7697     dm->boundary = NULL;
7698   }
7699 
7700   lastnext = &(dm->boundary);
7701   while (dsbound) {
7702     DMBoundary dmbound;
7703 
7704     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7705     dmbound->dsboundary = dsbound;
7706     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7707     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7708     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7709     *lastnext = dmbound;
7710     lastnext = &(dmbound->next);
7711     dsbound = dsbound->next;
7712   }
7713   PetscFunctionReturn(0);
7714 }
7715 
7716 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7717 {
7718   DMBoundary     b;
7719   PetscErrorCode ierr;
7720 
7721   PetscFunctionBegin;
7722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7723   PetscValidBoolPointer(isBd, 3);
7724   *isBd = PETSC_FALSE;
7725   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7726   b = dm->boundary;
7727   while (b && !(*isBd)) {
7728     DMLabel    label = b->label;
7729     DSBoundary dsb = b->dsboundary;
7730 
7731     if (label) {
7732       PetscInt i;
7733 
7734       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7735         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7736       }
7737     }
7738     b = b->next;
7739   }
7740   PetscFunctionReturn(0);
7741 }
7742 
7743 /*@C
7744   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
7745 
7746   Collective on DM
7747 
7748   Input Parameters:
7749 + dm      - The DM
7750 . time    - The time
7751 . funcs   - The coordinate functions to evaluate, one per field
7752 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7753 - mode    - The insertion mode for values
7754 
7755   Output Parameter:
7756 . X - vector
7757 
7758    Calling sequence of func:
7759 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7760 
7761 +  dim - The spatial dimension
7762 .  x   - The coordinates
7763 .  Nf  - The number of fields
7764 .  u   - The output field values
7765 -  ctx - optional user-defined function context
7766 
7767   Level: developer
7768 
7769 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7770 @*/
7771 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7772 {
7773   Vec            localX;
7774   PetscErrorCode ierr;
7775 
7776   PetscFunctionBegin;
7777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7778   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7779   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7780   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7781   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7782   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7783   PetscFunctionReturn(0);
7784 }
7785 
7786 /*@C
7787   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
7788 
7789   Not collective
7790 
7791   Input Parameters:
7792 + dm      - The DM
7793 . time    - The time
7794 . funcs   - The coordinate functions to evaluate, one per field
7795 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7796 - mode    - The insertion mode for values
7797 
7798   Output Parameter:
7799 . localX - vector
7800 
7801    Calling sequence of func:
7802 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7803 
7804 +  dim - The spatial dimension
7805 .  x   - The coordinates
7806 .  Nf  - The number of fields
7807 .  u   - The output field values
7808 -  ctx - optional user-defined function context
7809 
7810   Level: developer
7811 
7812 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7813 @*/
7814 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7815 {
7816   PetscErrorCode ierr;
7817 
7818   PetscFunctionBegin;
7819   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7820   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7821   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7822   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7823   PetscFunctionReturn(0);
7824 }
7825 
7826 /*@C
7827   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.
7828 
7829   Collective on DM
7830 
7831   Input Parameters:
7832 + dm      - The DM
7833 . time    - The time
7834 . label   - The DMLabel selecting the portion of the mesh for projection
7835 . funcs   - The coordinate functions to evaluate, one per field
7836 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7837 - mode    - The insertion mode for values
7838 
7839   Output Parameter:
7840 . X - vector
7841 
7842    Calling sequence of func:
7843 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7844 
7845 +  dim - The spatial dimension
7846 .  x   - The coordinates
7847 .  Nf  - The number of fields
7848 .  u   - The output field values
7849 -  ctx - optional user-defined function context
7850 
7851   Level: developer
7852 
7853 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
7854 @*/
7855 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)
7856 {
7857   Vec            localX;
7858   PetscErrorCode ierr;
7859 
7860   PetscFunctionBegin;
7861   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7862   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7863   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7864   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7865   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7866   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7867   PetscFunctionReturn(0);
7868 }
7869 
7870 /*@C
7871   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.
7872 
7873   Not collective
7874 
7875   Input Parameters:
7876 + dm      - The DM
7877 . time    - The time
7878 . label   - The DMLabel selecting the portion of the mesh for projection
7879 . funcs   - The coordinate functions to evaluate, one per field
7880 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7881 - mode    - The insertion mode for values
7882 
7883   Output Parameter:
7884 . localX - vector
7885 
7886    Calling sequence of func:
7887 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7888 
7889 +  dim - The spatial dimension
7890 .  x   - The coordinates
7891 .  Nf  - The number of fields
7892 .  u   - The output field values
7893 -  ctx - optional user-defined function context
7894 
7895   Level: developer
7896 
7897 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7898 @*/
7899 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)
7900 {
7901   PetscErrorCode ierr;
7902 
7903   PetscFunctionBegin;
7904   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7905   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7906   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7907   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7908   PetscFunctionReturn(0);
7909 }
7910 
7911 /*@C
7912   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
7913 
7914   Not collective
7915 
7916   Input Parameters:
7917 + dm      - The DM
7918 . time    - The time
7919 . localU  - The input field vector
7920 . funcs   - The functions to evaluate, one per field
7921 - mode    - The insertion mode for values
7922 
7923   Output Parameter:
7924 . localX  - The output vector
7925 
7926    Calling sequence of func:
7927 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7928 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7929 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7930 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7931 
7932 +  dim          - The spatial dimension
7933 .  Nf           - The number of input fields
7934 .  NfAux        - The number of input auxiliary fields
7935 .  uOff         - The offset of each field in u[]
7936 .  uOff_x       - The offset of each field in u_x[]
7937 .  u            - The field values at this point in space
7938 .  u_t          - The field time derivative at this point in space (or NULL)
7939 .  u_x          - The field derivatives at this point in space
7940 .  aOff         - The offset of each auxiliary field in u[]
7941 .  aOff_x       - The offset of each auxiliary field in u_x[]
7942 .  a            - The auxiliary field values at this point in space
7943 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7944 .  a_x          - The auxiliary field derivatives at this point in space
7945 .  t            - The current time
7946 .  x            - The coordinates of this point
7947 .  numConstants - The number of constants
7948 .  constants    - The value of each constant
7949 -  f            - The value of the function at this point in space
7950 
7951   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.
7952   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
7953   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
7954   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
7955 
7956   Level: intermediate
7957 
7958 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7959 @*/
7960 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7961                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7962                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7963                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7964                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7965                                    InsertMode mode, Vec localX)
7966 {
7967   PetscErrorCode ierr;
7968 
7969   PetscFunctionBegin;
7970   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7971   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
7972   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
7973   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7974   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
7975   PetscFunctionReturn(0);
7976 }
7977 
7978 /*@C
7979   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.
7980 
7981   Not collective
7982 
7983   Input Parameters:
7984 + dm      - The DM
7985 . time    - The time
7986 . label   - The DMLabel marking the portion of the domain to output
7987 . numIds  - The number of label ids to use
7988 . ids     - The label ids to use for marking
7989 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
7990 . comps   - The components to set in the output, or NULL for all components
7991 . localU  - The input field vector
7992 . funcs   - The functions to evaluate, one per field
7993 - mode    - The insertion mode for values
7994 
7995   Output Parameter:
7996 . localX  - The output vector
7997 
7998    Calling sequence of func:
7999 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8000 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8001 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8002 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8003 
8004 +  dim          - The spatial dimension
8005 .  Nf           - The number of input fields
8006 .  NfAux        - The number of input auxiliary fields
8007 .  uOff         - The offset of each field in u[]
8008 .  uOff_x       - The offset of each field in u_x[]
8009 .  u            - The field values at this point in space
8010 .  u_t          - The field time derivative at this point in space (or NULL)
8011 .  u_x          - The field derivatives at this point in space
8012 .  aOff         - The offset of each auxiliary field in u[]
8013 .  aOff_x       - The offset of each auxiliary field in u_x[]
8014 .  a            - The auxiliary field values at this point in space
8015 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8016 .  a_x          - The auxiliary field derivatives at this point in space
8017 .  t            - The current time
8018 .  x            - The coordinates of this point
8019 .  numConstants - The number of constants
8020 .  constants    - The value of each constant
8021 -  f            - The value of the function at this point in space
8022 
8023   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.
8024   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
8025   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8026   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8027 
8028   Level: intermediate
8029 
8030 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8031 @*/
8032 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8033                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8034                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8035                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8036                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8037                                         InsertMode mode, Vec localX)
8038 {
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8043   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8044   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8045   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8046   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8047   PetscFunctionReturn(0);
8048 }
8049 
8050 /*@C
8051   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8052 
8053   Input Parameters:
8054 + dm    - The DM
8055 . time  - The time
8056 . funcs - The functions to evaluate for each field component
8057 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8058 - X     - The coefficient vector u_h, a global vector
8059 
8060   Output Parameter:
8061 . diff - The diff ||u - u_h||_2
8062 
8063   Level: developer
8064 
8065 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8066 @*/
8067 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8068 {
8069   PetscErrorCode ierr;
8070 
8071   PetscFunctionBegin;
8072   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8073   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8074   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8075   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8076   PetscFunctionReturn(0);
8077 }
8078 
8079 /*@C
8080   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8081 
8082   Collective on dm
8083 
8084   Input Parameters:
8085 + dm    - The DM
8086 , time  - The time
8087 . funcs - The gradient functions to evaluate for each field component
8088 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8089 . X     - The coefficient vector u_h, a global vector
8090 - n     - The vector to project along
8091 
8092   Output Parameter:
8093 . diff - The diff ||(grad u - grad u_h) . n||_2
8094 
8095   Level: developer
8096 
8097 .seealso: DMProjectFunction(), DMComputeL2Diff()
8098 @*/
8099 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)
8100 {
8101   PetscErrorCode ierr;
8102 
8103   PetscFunctionBegin;
8104   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8105   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8106   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8107   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
8108   PetscFunctionReturn(0);
8109 }
8110 
8111 /*@C
8112   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8113 
8114   Collective on dm
8115 
8116   Input Parameters:
8117 + dm    - The DM
8118 . time  - The time
8119 . funcs - The functions to evaluate for each field component
8120 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8121 - X     - The coefficient vector u_h, a global vector
8122 
8123   Output Parameter:
8124 . diff - The array of differences, ||u^f - u^f_h||_2
8125 
8126   Level: developer
8127 
8128 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8129 @*/
8130 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8131 {
8132   PetscErrorCode ierr;
8133 
8134   PetscFunctionBegin;
8135   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8136   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8137   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8138   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8139   PetscFunctionReturn(0);
8140 }
8141 
8142 /*@C
8143   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8144                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8145 
8146   Collective on dm
8147 
8148   Input parameters:
8149 + dm - the pre-adaptation DM object
8150 - label - label with the flags
8151 
8152   Output parameters:
8153 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8154 
8155   Level: intermediate
8156 
8157 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8158 @*/
8159 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8160 {
8161   PetscErrorCode ierr;
8162 
8163   PetscFunctionBegin;
8164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8165   PetscValidPointer(label,2);
8166   PetscValidPointer(dmAdapt,3);
8167   *dmAdapt = NULL;
8168   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8169   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
8170   PetscFunctionReturn(0);
8171 }
8172 
8173 /*@C
8174   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8175 
8176   Input Parameters:
8177 + dm - The DM object
8178 . metric - The metric to which the mesh is adapted, defined vertex-wise.
8179 - 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_".
8180 
8181   Output Parameter:
8182 . dmAdapt  - Pointer to the DM object containing the adapted mesh
8183 
8184   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8185 
8186   Level: advanced
8187 
8188 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8189 @*/
8190 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8191 {
8192   PetscErrorCode ierr;
8193 
8194   PetscFunctionBegin;
8195   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8196   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
8197   if (bdLabel) PetscValidPointer(bdLabel, 3);
8198   PetscValidPointer(dmAdapt, 4);
8199   *dmAdapt = NULL;
8200   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8201   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
8202   PetscFunctionReturn(0);
8203 }
8204 
8205 /*@C
8206  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8207 
8208  Not Collective
8209 
8210  Input Parameter:
8211 .  dm    - The DM
8212 
8213  Output Parameters:
8214 +  nranks - the number of neighbours
8215 -  ranks - the neighbors ranks
8216 
8217  Notes:
8218  Do not free the array, it is freed when the DM is destroyed.
8219 
8220  Level: beginner
8221 
8222  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8223 @*/
8224 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8225 {
8226   PetscErrorCode ierr;
8227 
8228   PetscFunctionBegin;
8229   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8230   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8231   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
8232   PetscFunctionReturn(0);
8233 }
8234 
8235 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8236 
8237 /*
8238     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8239     This has be a different function because it requires DM which is not defined in the Mat library
8240 */
8241 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8242 {
8243   PetscErrorCode ierr;
8244 
8245   PetscFunctionBegin;
8246   if (coloring->ctype == IS_COLORING_LOCAL) {
8247     Vec x1local;
8248     DM  dm;
8249     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8250     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8251     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
8252     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8253     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8254     x1   = x1local;
8255   }
8256   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
8257   if (coloring->ctype == IS_COLORING_LOCAL) {
8258     DM  dm;
8259     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8260     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
8261   }
8262   PetscFunctionReturn(0);
8263 }
8264 
8265 /*@
8266     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
8267 
8268     Input Parameter:
8269 .    coloring - the MatFDColoring object
8270 
8271     Developer Notes:
8272     this routine exists because the PETSc Mat library does not know about the DM objects
8273 
8274     Level: advanced
8275 
8276 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8277 @*/
8278 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8279 {
8280   PetscFunctionBegin;
8281   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8282   PetscFunctionReturn(0);
8283 }
8284 
8285 /*@
8286     DMGetCompatibility - determine if two DMs are compatible
8287 
8288     Collective
8289 
8290     Input Parameters:
8291 +    dm1 - the first DM
8292 -    dm2 - the second DM
8293 
8294     Output Parameters:
8295 +    compatible - whether or not the two DMs are compatible
8296 -    set - whether or not the compatible value was set
8297 
8298     Notes:
8299     Two DMs are deemed compatible if they represent the same parallel decomposition
8300     of the same topology. This implies that the section (field data) on one
8301     "makes sense" with respect to the topology and parallel decomposition of the other.
8302     Loosely speaking, compatible DMs represent the same domain and parallel
8303     decomposition, but hold different data.
8304 
8305     Typically, one would confirm compatibility if intending to simultaneously iterate
8306     over a pair of vectors obtained from different DMs.
8307 
8308     For example, two DMDA objects are compatible if they have the same local
8309     and global sizes and the same stencil width. They can have different numbers
8310     of degrees of freedom per node. Thus, one could use the node numbering from
8311     either DM in bounds for a loop over vectors derived from either DM.
8312 
8313     Consider the operation of summing data living on a 2-dof DMDA to data living
8314     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8315 .vb
8316   ...
8317   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
8318   if (set && compatible)  {
8319     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8320     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8321     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
8322     for (j=y; j<y+n; ++j) {
8323       for (i=x; i<x+m, ++i) {
8324         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8325       }
8326     }
8327     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8328     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8329   } else {
8330     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8331   }
8332   ...
8333 .ve
8334 
8335     Checking compatibility might be expensive for a given implementation of DM,
8336     or might be impossible to unambiguously confirm or deny. For this reason,
8337     this function may decline to determine compatibility, and hence users should
8338     always check the "set" output parameter.
8339 
8340     A DM is always compatible with itself.
8341 
8342     In the current implementation, DMs which live on "unequal" communicators
8343     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8344     incompatible.
8345 
8346     This function is labeled "Collective," as information about all subdomains
8347     is required on each rank. However, in DM implementations which store all this
8348     information locally, this function may be merely "Logically Collective".
8349 
8350     Developer Notes:
8351     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8352     iff B is compatible with A. Thus, this function checks the implementations
8353     of both dm and dmc (if they are of different types), attempting to determine
8354     compatibility. It is left to DM implementers to ensure that symmetry is
8355     preserved. The simplest way to do this is, when implementing type-specific
8356     logic for this function, is to check for existing logic in the implementation
8357     of other DM types and let *set = PETSC_FALSE if found.
8358 
8359     Level: advanced
8360 
8361 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8362 @*/
8363 
8364 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8365 {
8366   PetscErrorCode ierr;
8367   PetscMPIInt    compareResult;
8368   DMType         type,type2;
8369   PetscBool      sameType;
8370 
8371   PetscFunctionBegin;
8372   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
8373   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
8374 
8375   /* Declare a DM compatible with itself */
8376   if (dm1 == dm2) {
8377     *set = PETSC_TRUE;
8378     *compatible = PETSC_TRUE;
8379     PetscFunctionReturn(0);
8380   }
8381 
8382   /* Declare a DM incompatible with a DM that lives on an "unequal"
8383      communicator. Note that this does not preclude compatibility with
8384      DMs living on "congruent" or "similar" communicators, but this must be
8385      determined by the implementation-specific logic */
8386   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
8387   if (compareResult == MPI_UNEQUAL) {
8388     *set = PETSC_TRUE;
8389     *compatible = PETSC_FALSE;
8390     PetscFunctionReturn(0);
8391   }
8392 
8393   /* Pass to the implementation-specific routine, if one exists. */
8394   if (dm1->ops->getcompatibility) {
8395     ierr = (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);CHKERRQ(ierr);
8396     if (*set) PetscFunctionReturn(0);
8397   }
8398 
8399   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8400      with an implementation of this function from dm2 */
8401   ierr = DMGetType(dm1,&type);CHKERRQ(ierr);
8402   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
8403   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
8404   if (!sameType && dm2->ops->getcompatibility) {
8405     ierr = (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set);CHKERRQ(ierr); /* Note argument order */
8406   } else {
8407     *set = PETSC_FALSE;
8408   }
8409   PetscFunctionReturn(0);
8410 }
8411 
8412 /*@C
8413   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
8414 
8415   Logically Collective on DM
8416 
8417   Input Parameters:
8418 + DM - the DM
8419 . f - the monitor function
8420 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8421 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8422 
8423   Options Database Keys:
8424 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8425                             does not cancel those set via the options database.
8426 
8427   Notes:
8428   Several different monitoring routines may be set by calling
8429   DMMonitorSet() multiple times; all will be called in the
8430   order in which they were set.
8431 
8432   Fortran Notes:
8433   Only a single monitor function can be set for each DM object
8434 
8435   Level: intermediate
8436 
8437 .seealso: DMMonitorCancel()
8438 @*/
8439 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8440 {
8441   PetscInt       m;
8442   PetscErrorCode ierr;
8443 
8444   PetscFunctionBegin;
8445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8446   for (m = 0; m < dm->numbermonitors; ++m) {
8447     PetscBool identical;
8448 
8449     ierr = PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);CHKERRQ(ierr);
8450     if (identical) PetscFunctionReturn(0);
8451   }
8452   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8453   dm->monitor[dm->numbermonitors]          = f;
8454   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8455   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8456   PetscFunctionReturn(0);
8457 }
8458 
8459 /*@
8460   DMMonitorCancel - Clears all the monitor functions for a DM object.
8461 
8462   Logically Collective on DM
8463 
8464   Input Parameter:
8465 . dm - the DM
8466 
8467   Options Database Key:
8468 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8469   into a code by calls to DMonitorSet(), but does not cancel those
8470   set via the options database
8471 
8472   Notes:
8473   There is no way to clear one specific monitor from a DM object.
8474 
8475   Level: intermediate
8476 
8477 .seealso: DMMonitorSet()
8478 @*/
8479 PetscErrorCode DMMonitorCancel(DM dm)
8480 {
8481   PetscErrorCode ierr;
8482   PetscInt       m;
8483 
8484   PetscFunctionBegin;
8485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8486   for (m = 0; m < dm->numbermonitors; ++m) {
8487     if (dm->monitordestroy[m]) {ierr = (*dm->monitordestroy[m])(&dm->monitorcontext[m]);CHKERRQ(ierr);}
8488   }
8489   dm->numbermonitors = 0;
8490   PetscFunctionReturn(0);
8491 }
8492 
8493 /*@C
8494   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8495 
8496   Collective on DM
8497 
8498   Input Parameters:
8499 + dm   - DM object you wish to monitor
8500 . name - the monitor type one is seeking
8501 . help - message indicating what monitoring is done
8502 . manual - manual page for the monitor
8503 . monitor - the monitor function
8504 - 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
8505 
8506   Output Parameter:
8507 . flg - Flag set if the monitor was created
8508 
8509   Level: developer
8510 
8511 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8512           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8513           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8514           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8515           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8516           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8517           PetscOptionsFList(), PetscOptionsEList()
8518 @*/
8519 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8520 {
8521   PetscViewer       viewer;
8522   PetscViewerFormat format;
8523   PetscErrorCode    ierr;
8524 
8525   PetscFunctionBegin;
8526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8527   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);CHKERRQ(ierr);
8528   if (*flg) {
8529     PetscViewerAndFormat *vf;
8530 
8531     ierr = PetscViewerAndFormatCreate(viewer, format, &vf);CHKERRQ(ierr);
8532     ierr = PetscObjectDereference((PetscObject) viewer);CHKERRQ(ierr);
8533     if (monitorsetup) {ierr = (*monitorsetup)(dm, vf);CHKERRQ(ierr);}
8534     ierr = DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);CHKERRQ(ierr);
8535   }
8536   PetscFunctionReturn(0);
8537 }
8538 
8539 /*@
8540    DMMonitor - runs the user provided monitor routines, if they exist
8541 
8542    Collective on DM
8543 
8544    Input Parameters:
8545 .  dm - The DM
8546 
8547    Level: developer
8548 
8549 .seealso: DMMonitorSet()
8550 @*/
8551 PetscErrorCode DMMonitor(DM dm)
8552 {
8553   PetscInt       m;
8554   PetscErrorCode ierr;
8555 
8556   PetscFunctionBegin;
8557   if (!dm) PetscFunctionReturn(0);
8558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8559   for (m = 0; m < dm->numbermonitors; ++m) {
8560     ierr = (*dm->monitor[m])(dm, dm->monitorcontext[m]);CHKERRQ(ierr);
8561   }
8562   PetscFunctionReturn(0);
8563 }
8564