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