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