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