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