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