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