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