xref: /petsc/src/dm/interface/dm.c (revision ef0bb6c736604ce380bf8bea4ebd4a7bda431d97)
1 #include <petsc/private/dmimpl.h>           /*I      "petscdm.h"          I*/
2 #include <petsc/private/dmlabelimpl.h>      /*I      "petscdmlabel.h"     I*/
3 #include <petsc/private/petscdsimpl.h>      /*I      "petscds.h"     I*/
4 #include <petscdmplex.h>
5 #include <petscdmfield.h>
6 #include <petscsf.h>
7 #include <petscds.h>
8 
9 PetscClassId  DM_CLASSID;
10 PetscClassId  DMLABEL_CLASSID;
11 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load;
12 
13 const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_",0};
14 const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_",0};
15 
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: DMDestroy(), 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   ierr = PetscLogEventBegin(DM_Load,viewer,0,0,0);CHKERRQ(ierr);
3759   if (isbinary) {
3760     PetscInt classid;
3761     char     type[256];
3762 
3763     ierr = PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);CHKERRQ(ierr);
3764     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3765     ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
3766     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
3767     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3768   } else if (ishdf5) {
3769     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3770   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3771   ierr = PetscLogEventEnd(DM_Load,viewer,0,0,0);CHKERRQ(ierr);
3772   PetscFunctionReturn(0);
3773 }
3774 
3775 /*@
3776   DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
3777 
3778   Not collective
3779 
3780   Input Parameter:
3781 . dm - the DM
3782 
3783   Output Parameters:
3784 + lmin - local minimum coordinates (length coord dim, optional)
3785 - lmax - local maximim coordinates (length coord dim, optional)
3786 
3787   Level: beginner
3788 
3789   Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
3790 
3791 
3792 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3793 @*/
3794 PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3795 {
3796   Vec                coords = NULL;
3797   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3798   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3799   const PetscScalar *local_coords;
3800   PetscInt           N, Ni;
3801   PetscInt           cdim, i, j;
3802   PetscErrorCode     ierr;
3803 
3804   PetscFunctionBegin;
3805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3806   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
3807   ierr = DMGetCoordinates(dm, &coords);CHKERRQ(ierr);
3808   if (coords) {
3809     ierr = VecGetArrayRead(coords, &local_coords);CHKERRQ(ierr);
3810     ierr = VecGetLocalSize(coords, &N);CHKERRQ(ierr);
3811     Ni   = N/cdim;
3812     for (i = 0; i < Ni; ++i) {
3813       for (j = 0; j < 3; ++j) {
3814         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3815         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3816       }
3817     }
3818     ierr = VecRestoreArrayRead(coords, &local_coords);CHKERRQ(ierr);
3819   } else {
3820     PetscBool isda;
3821 
3822     ierr = PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);CHKERRQ(ierr);
3823     if (isda) {ierr = DMGetLocalBoundingIndices_DMDA(dm, min, max);CHKERRQ(ierr);}
3824   }
3825   if (lmin) {ierr = PetscArraycpy(lmin, min, cdim);CHKERRQ(ierr);}
3826   if (lmax) {ierr = PetscArraycpy(lmax, max, cdim);CHKERRQ(ierr);}
3827   PetscFunctionReturn(0);
3828 }
3829 
3830 /*@
3831   DMGetBoundingBox - Returns the global bounding box for the DM.
3832 
3833   Collective
3834 
3835   Input Parameter:
3836 . dm - the DM
3837 
3838   Output Parameters:
3839 + gmin - global minimum coordinates (length coord dim, optional)
3840 - gmax - global maximim coordinates (length coord dim, optional)
3841 
3842   Level: beginner
3843 
3844 .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3845 @*/
3846 PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3847 {
3848   PetscReal      lmin[3], lmax[3];
3849   PetscInt       cdim;
3850   PetscMPIInt    count;
3851   PetscErrorCode ierr;
3852 
3853   PetscFunctionBegin;
3854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3855   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
3856   ierr = PetscMPIIntCast(cdim, &count);CHKERRQ(ierr);
3857   ierr = DMGetLocalBoundingBox(dm, lmin, lmax);CHKERRQ(ierr);
3858   if (gmin) {ierr = MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);}
3859   if (gmax) {ierr = MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);}
3860   PetscFunctionReturn(0);
3861 }
3862 
3863 /******************************** FEM Support **********************************/
3864 
3865 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3866 {
3867   PetscInt       f;
3868   PetscErrorCode ierr;
3869 
3870   PetscFunctionBegin;
3871   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3872   for (f = 0; f < len; ++f) {
3873     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3874   }
3875   PetscFunctionReturn(0);
3876 }
3877 
3878 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3879 {
3880   PetscInt       f, g;
3881   PetscErrorCode ierr;
3882 
3883   PetscFunctionBegin;
3884   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3885   for (f = 0; f < rows; ++f) {
3886     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3887     for (g = 0; g < cols; ++g) {
3888       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3889     }
3890     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3891   }
3892   PetscFunctionReturn(0);
3893 }
3894 
3895 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3896 {
3897   PetscInt          localSize, bs;
3898   PetscMPIInt       size;
3899   Vec               x, xglob;
3900   const PetscScalar *xarray;
3901   PetscErrorCode    ierr;
3902 
3903   PetscFunctionBegin;
3904   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);CHKERRQ(ierr);
3905   ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3906   ierr = VecCopy(X, x);CHKERRQ(ierr);
3907   ierr = VecChop(x, tol);CHKERRQ(ierr);
3908   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);CHKERRQ(ierr);
3909   if (size > 1) {
3910     ierr = VecGetLocalSize(x,&localSize);CHKERRQ(ierr);
3911     ierr = VecGetArrayRead(x,&xarray);CHKERRQ(ierr);
3912     ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
3913     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);CHKERRQ(ierr);
3914   } else {
3915     xglob = x;
3916   }
3917   ierr = VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));CHKERRQ(ierr);
3918   if (size > 1) {
3919     ierr = VecDestroy(&xglob);CHKERRQ(ierr);
3920     ierr = VecRestoreArrayRead(x,&xarray);CHKERRQ(ierr);
3921   }
3922   ierr = VecDestroy(&x);CHKERRQ(ierr);
3923   PetscFunctionReturn(0);
3924 }
3925 
3926 /*@
3927   DMGetSection - Get the PetscSection encoding the local data layout for the DM.   This is equivalent to DMGetLocalSection(). Deprecated in v3.12
3928 
3929   Input Parameter:
3930 . dm - The DM
3931 
3932   Output Parameter:
3933 . section - The PetscSection
3934 
3935   Options Database Keys:
3936 . -dm_petscsection_view - View the Section created by the DM
3937 
3938   Level: advanced
3939 
3940   Notes:
3941   Use DMGetLocalSection() in new code.
3942 
3943   This gets a borrowed reference, so the user should not destroy this PetscSection.
3944 
3945 .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
3946 @*/
3947 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3948 {
3949   PetscErrorCode ierr;
3950 
3951   PetscFunctionBegin;
3952   ierr = DMGetLocalSection(dm,section);CHKERRQ(ierr);
3953   PetscFunctionReturn(0);
3954 }
3955 
3956 /*@
3957   DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
3958 
3959   Input Parameter:
3960 . dm - The DM
3961 
3962   Output Parameter:
3963 . section - The PetscSection
3964 
3965   Options Database Keys:
3966 . -dm_petscsection_view - View the Section created by the DM
3967 
3968   Level: intermediate
3969 
3970   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3971 
3972 .seealso: DMSetLocalSection(), DMGetGlobalSection()
3973 @*/
3974 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
3975 {
3976   PetscErrorCode ierr;
3977 
3978   PetscFunctionBegin;
3979   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3980   PetscValidPointer(section, 2);
3981   if (!dm->localSection && dm->ops->createlocalsection) {
3982     PetscInt d;
3983 
3984     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {ierr = PetscDSSetFromOptions(dm->probs[d].ds);CHKERRQ(ierr);}
3985     ierr = (*dm->ops->createlocalsection)(dm);CHKERRQ(ierr);
3986     if (dm->localSection) {ierr = PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);}
3987   }
3988   *section = dm->localSection;
3989   PetscFunctionReturn(0);
3990 }
3991 
3992 /*@
3993   DMSetSection - Set the PetscSection encoding the local data layout for the DM.  This is equivalent to DMSetLocalSection(). Deprecated in v3.12
3994 
3995   Input Parameters:
3996 + dm - The DM
3997 - section - The PetscSection
3998 
3999   Level: advanced
4000 
4001   Notes:
4002   Use DMSetLocalSection() in new code.
4003 
4004   Any existing Section will be destroyed
4005 
4006 .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4007 @*/
4008 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4009 {
4010   PetscErrorCode ierr;
4011 
4012   PetscFunctionBegin;
4013   ierr = DMSetLocalSection(dm,section);CHKERRQ(ierr);
4014   PetscFunctionReturn(0);
4015 }
4016 
4017 /*@
4018   DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
4019 
4020   Input Parameters:
4021 + dm - The DM
4022 - section - The PetscSection
4023 
4024   Level: intermediate
4025 
4026   Note: Any existing Section will be destroyed
4027 
4028 .seealso: DMGetLocalSection(), DMSetGlobalSection()
4029 @*/
4030 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4031 {
4032   PetscInt       numFields = 0;
4033   PetscInt       f;
4034   PetscErrorCode ierr;
4035 
4036   PetscFunctionBegin;
4037   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4038   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4039   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
4040   ierr = PetscSectionDestroy(&dm->localSection);CHKERRQ(ierr);
4041   dm->localSection = section;
4042   if (section) {ierr = PetscSectionGetNumFields(dm->localSection, &numFields);CHKERRQ(ierr);}
4043   if (numFields) {
4044     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
4045     for (f = 0; f < numFields; ++f) {
4046       PetscObject disc;
4047       const char *name;
4048 
4049       ierr = PetscSectionGetFieldName(dm->localSection, f, &name);CHKERRQ(ierr);
4050       ierr = DMGetField(dm, f, NULL, &disc);CHKERRQ(ierr);
4051       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
4052     }
4053   }
4054   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4055   ierr = PetscSectionDestroy(&dm->globalSection);CHKERRQ(ierr);
4056   PetscFunctionReturn(0);
4057 }
4058 
4059 /*@
4060   DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4061 
4062   not collective
4063 
4064   Input Parameter:
4065 . dm - The DM
4066 
4067   Output Parameter:
4068 + 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.
4069 - 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.
4070 
4071   Level: advanced
4072 
4073   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
4074 
4075 .seealso: DMSetDefaultConstraints()
4076 @*/
4077 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4078 {
4079   PetscErrorCode ierr;
4080 
4081   PetscFunctionBegin;
4082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4083   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
4084   if (section) {*section = dm->defaultConstraintSection;}
4085   if (mat) {*mat = dm->defaultConstraintMat;}
4086   PetscFunctionReturn(0);
4087 }
4088 
4089 /*@
4090   DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4091 
4092   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().
4093 
4094   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.
4095 
4096   collective on dm
4097 
4098   Input Parameters:
4099 + dm - The DM
4100 + 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).
4101 - 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).
4102 
4103   Level: advanced
4104 
4105   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
4106 
4107 .seealso: DMGetDefaultConstraints()
4108 @*/
4109 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4110 {
4111   PetscMPIInt result;
4112   PetscErrorCode ierr;
4113 
4114   PetscFunctionBegin;
4115   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4116   if (section) {
4117     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4118     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
4119     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4120   }
4121   if (mat) {
4122     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
4123     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
4124     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4125   }
4126   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
4127   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
4128   dm->defaultConstraintSection = section;
4129   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
4130   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
4131   dm->defaultConstraintMat = mat;
4132   PetscFunctionReturn(0);
4133 }
4134 
4135 #if defined(PETSC_USE_DEBUG)
4136 /*
4137   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4138 
4139   Input Parameters:
4140 + dm - The DM
4141 . localSection - PetscSection describing the local data layout
4142 - globalSection - PetscSection describing the global data layout
4143 
4144   Level: intermediate
4145 
4146 .seealso: DMGetSectionSF(), DMSetSectionSF()
4147 */
4148 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4149 {
4150   MPI_Comm        comm;
4151   PetscLayout     layout;
4152   const PetscInt *ranges;
4153   PetscInt        pStart, pEnd, p, nroots;
4154   PetscMPIInt     size, rank;
4155   PetscBool       valid = PETSC_TRUE, gvalid;
4156   PetscErrorCode  ierr;
4157 
4158   PetscFunctionBegin;
4159   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4160   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4161   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
4162   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4163   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
4164   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
4165   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
4166   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
4167   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
4168   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
4169   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
4170   for (p = pStart; p < pEnd; ++p) {
4171     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
4172 
4173     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
4174     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
4175     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
4176     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4177     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4178     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
4179     if (!gdof) continue; /* Censored point */
4180     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;}
4181     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;}
4182     if (gdof < 0) {
4183       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4184       for (d = 0; d < gsize; ++d) {
4185         PetscInt offset = -(goff+1) + d, r;
4186 
4187         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
4188         if (r < 0) r = -(r+2);
4189         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;}
4190       }
4191     }
4192   }
4193   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
4194   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
4195   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
4196   if (!gvalid) {
4197     ierr = DMView(dm, NULL);CHKERRQ(ierr);
4198     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4199   }
4200   PetscFunctionReturn(0);
4201 }
4202 #endif
4203 
4204 /*@
4205   DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4206 
4207   Collective on dm
4208 
4209   Input Parameter:
4210 . dm - The DM
4211 
4212   Output Parameter:
4213 . section - The PetscSection
4214 
4215   Level: intermediate
4216 
4217   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4218 
4219 .seealso: DMSetLocalSection(), DMGetLocalSection()
4220 @*/
4221 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4222 {
4223   PetscErrorCode ierr;
4224 
4225   PetscFunctionBegin;
4226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4227   PetscValidPointer(section, 2);
4228   if (!dm->globalSection) {
4229     PetscSection s;
4230 
4231     ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
4232     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4233     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4234     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);CHKERRQ(ierr);
4235     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
4236     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);CHKERRQ(ierr);
4237     ierr = PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");CHKERRQ(ierr);
4238   }
4239   *section = dm->globalSection;
4240   PetscFunctionReturn(0);
4241 }
4242 
4243 /*@
4244   DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4245 
4246   Input Parameters:
4247 + dm - The DM
4248 - section - The PetscSection, or NULL
4249 
4250   Level: intermediate
4251 
4252   Note: Any existing Section will be destroyed
4253 
4254 .seealso: DMGetGlobalSection(), DMSetLocalSection()
4255 @*/
4256 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4257 {
4258   PetscErrorCode ierr;
4259 
4260   PetscFunctionBegin;
4261   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4262   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4263   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
4264   ierr = PetscSectionDestroy(&dm->globalSection);CHKERRQ(ierr);
4265   dm->globalSection = section;
4266 #if defined(PETSC_USE_DEBUG)
4267   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);CHKERRQ(ierr);}
4268 #endif
4269   PetscFunctionReturn(0);
4270 }
4271 
4272 /*@
4273   DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4274   it is created from the default PetscSection layouts in the DM.
4275 
4276   Input Parameter:
4277 . dm - The DM
4278 
4279   Output Parameter:
4280 . sf - The PetscSF
4281 
4282   Level: intermediate
4283 
4284   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4285 
4286 .seealso: DMSetSectionSF(), DMCreateSectionSF()
4287 @*/
4288 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4289 {
4290   PetscInt       nroots;
4291   PetscErrorCode ierr;
4292 
4293   PetscFunctionBegin;
4294   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4295   PetscValidPointer(sf, 2);
4296   if (!dm->sectionSF) {
4297     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);CHKERRQ(ierr);
4298   }
4299   ierr = PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
4300   if (nroots < 0) {
4301     PetscSection section, gSection;
4302 
4303     ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
4304     if (section) {
4305       ierr = DMGetGlobalSection(dm, &gSection);CHKERRQ(ierr);
4306       ierr = DMCreateSectionSF(dm, section, gSection);CHKERRQ(ierr);
4307     } else {
4308       *sf = NULL;
4309       PetscFunctionReturn(0);
4310     }
4311   }
4312   *sf = dm->sectionSF;
4313   PetscFunctionReturn(0);
4314 }
4315 
4316 /*@
4317   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4318 
4319   Input Parameters:
4320 + dm - The DM
4321 - sf - The PetscSF
4322 
4323   Level: intermediate
4324 
4325   Note: Any previous SF is destroyed
4326 
4327 .seealso: DMGetSectionSF(), DMCreateSectionSF()
4328 @*/
4329 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4330 {
4331   PetscErrorCode ierr;
4332 
4333   PetscFunctionBegin;
4334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4335   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4336   ierr = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4337   ierr = PetscSFDestroy(&dm->sectionSF);CHKERRQ(ierr);
4338   dm->sectionSF = sf;
4339   PetscFunctionReturn(0);
4340 }
4341 
4342 /*@C
4343   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4344   describing the data layout.
4345 
4346   Input Parameters:
4347 + dm - The DM
4348 . localSection - PetscSection describing the local data layout
4349 - globalSection - PetscSection describing the global data layout
4350 
4351   Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4352 
4353   Level: developer
4354 
4355   Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4356                   directly into the DM, perhaps this function should not take the local and global sections as
4357                   input and should just obtain them from the DM?
4358 
4359 .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4360 @*/
4361 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4362 {
4363   MPI_Comm       comm;
4364   PetscLayout    layout;
4365   const PetscInt *ranges;
4366   PetscInt       *local;
4367   PetscSFNode    *remote;
4368   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4369   PetscMPIInt    size, rank;
4370   PetscErrorCode ierr;
4371 
4372   PetscFunctionBegin;
4373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4374   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4375   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
4376   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4377   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
4378   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
4379   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
4380   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
4381   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
4382   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
4383   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
4384   for (p = pStart; p < pEnd; ++p) {
4385     PetscInt gdof, gcdof;
4386 
4387     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4388     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4389     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));
4390     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4391   }
4392   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
4393   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
4394   for (p = pStart, l = 0; p < pEnd; ++p) {
4395     const PetscInt *cind;
4396     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
4397 
4398     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
4399     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
4400     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
4401     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
4402     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4403     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4404     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
4405     if (!gdof) continue; /* Censored point */
4406     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4407     if (gsize != dof-cdof) {
4408       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);
4409       cdof = 0; /* Ignore constraints */
4410     }
4411     for (d = 0, c = 0; d < dof; ++d) {
4412       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4413       local[l+d-c] = off+d;
4414     }
4415     if (gdof < 0) {
4416       for (d = 0; d < gsize; ++d, ++l) {
4417         PetscInt offset = -(goff+1) + d, r;
4418 
4419         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
4420         if (r < 0) r = -(r+2);
4421         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);
4422         remote[l].rank  = r;
4423         remote[l].index = offset - ranges[r];
4424       }
4425     } else {
4426       for (d = 0; d < gsize; ++d, ++l) {
4427         remote[l].rank  = rank;
4428         remote[l].index = goff+d - ranges[rank];
4429       }
4430     }
4431   }
4432   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4433   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
4434   ierr = PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
4435   PetscFunctionReturn(0);
4436 }
4437 
4438 /*@
4439   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4440 
4441   Input Parameter:
4442 . dm - The DM
4443 
4444   Output Parameter:
4445 . sf - The PetscSF
4446 
4447   Level: intermediate
4448 
4449   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4450 
4451 .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4452 @*/
4453 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4454 {
4455   PetscFunctionBegin;
4456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4457   PetscValidPointer(sf, 2);
4458   *sf = dm->sf;
4459   PetscFunctionReturn(0);
4460 }
4461 
4462 /*@
4463   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4464 
4465   Input Parameters:
4466 + dm - The DM
4467 - sf - The PetscSF
4468 
4469   Level: intermediate
4470 
4471 .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4472 @*/
4473 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4474 {
4475   PetscErrorCode ierr;
4476 
4477   PetscFunctionBegin;
4478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4479   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4480   ierr = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4481   ierr = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
4482   dm->sf = sf;
4483   PetscFunctionReturn(0);
4484 }
4485 
4486 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4487 {
4488   PetscClassId   id;
4489   PetscErrorCode ierr;
4490 
4491   PetscFunctionBegin;
4492   ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
4493   if (id == PETSCFE_CLASSID) {
4494     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4495   } else if (id == PETSCFV_CLASSID) {
4496     ierr = DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
4497   } else {
4498     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4499   }
4500   PetscFunctionReturn(0);
4501 }
4502 
4503 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4504 {
4505   RegionField   *tmpr;
4506   PetscInt       Nf = dm->Nf, f;
4507   PetscErrorCode ierr;
4508 
4509   PetscFunctionBegin;
4510   if (Nf >= NfNew) PetscFunctionReturn(0);
4511   ierr = PetscMalloc1(NfNew, &tmpr);CHKERRQ(ierr);
4512   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4513   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4514   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4515   dm->Nf     = NfNew;
4516   dm->fields = tmpr;
4517   PetscFunctionReturn(0);
4518 }
4519 
4520 /*@
4521   DMClearFields - Remove all fields from the DM
4522 
4523   Logically collective on dm
4524 
4525   Input Parameter:
4526 . dm - The DM
4527 
4528   Level: intermediate
4529 
4530 .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4531 @*/
4532 PetscErrorCode DMClearFields(DM dm)
4533 {
4534   PetscInt       f;
4535   PetscErrorCode ierr;
4536 
4537   PetscFunctionBegin;
4538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4539   for (f = 0; f < dm->Nf; ++f) {
4540     ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4541     ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4542   }
4543   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4544   dm->fields = NULL;
4545   dm->Nf     = 0;
4546   PetscFunctionReturn(0);
4547 }
4548 
4549 /*@
4550   DMGetNumFields - Get the number of fields in the DM
4551 
4552   Not collective
4553 
4554   Input Parameter:
4555 . dm - The DM
4556 
4557   Output Parameter:
4558 . Nf - The number of fields
4559 
4560   Level: intermediate
4561 
4562 .seealso: DMSetNumFields(), DMSetField()
4563 @*/
4564 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4565 {
4566   PetscFunctionBegin;
4567   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4568   PetscValidIntPointer(numFields, 2);
4569   *numFields = dm->Nf;
4570   PetscFunctionReturn(0);
4571 }
4572 
4573 /*@
4574   DMSetNumFields - Set the number of fields in the DM
4575 
4576   Logically collective on dm
4577 
4578   Input Parameters:
4579 + dm - The DM
4580 - Nf - The number of fields
4581 
4582   Level: intermediate
4583 
4584 .seealso: DMGetNumFields(), DMSetField()
4585 @*/
4586 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4587 {
4588   PetscInt       Nf, f;
4589   PetscErrorCode ierr;
4590 
4591   PetscFunctionBegin;
4592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4593   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4594   for (f = Nf; f < numFields; ++f) {
4595     PetscContainer obj;
4596 
4597     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4598     ierr = DMAddField(dm, NULL, (PetscObject) obj);CHKERRQ(ierr);
4599     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4600   }
4601   PetscFunctionReturn(0);
4602 }
4603 
4604 /*@
4605   DMGetField - Return the discretization object for a given DM field
4606 
4607   Not collective
4608 
4609   Input Parameters:
4610 + dm - The DM
4611 - f  - The field number
4612 
4613   Output Parameters:
4614 + label - The label indicating the support of the field, or NULL for the entire mesh
4615 - field - The discretization object
4616 
4617   Level: intermediate
4618 
4619 .seealso: DMAddField(), DMSetField()
4620 @*/
4621 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4622 {
4623   PetscFunctionBegin;
4624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4625   PetscValidPointer(field, 3);
4626   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);
4627   if (label) *label = dm->fields[f].label;
4628   if (field) *field = dm->fields[f].disc;
4629   PetscFunctionReturn(0);
4630 }
4631 
4632 /*@
4633   DMSetField - Set the discretization object for a given DM field
4634 
4635   Logically collective on dm
4636 
4637   Input Parameters:
4638 + dm    - The DM
4639 . f     - The field number
4640 . label - The label indicating the support of the field, or NULL for the entire mesh
4641 - field - The discretization object
4642 
4643   Level: intermediate
4644 
4645 .seealso: DMAddField(), DMGetField()
4646 @*/
4647 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4648 {
4649   PetscErrorCode ierr;
4650 
4651   PetscFunctionBegin;
4652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4653   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4654   PetscValidHeader(field, 4);
4655   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4656   ierr = DMFieldEnlarge_Static(dm, f+1);CHKERRQ(ierr);
4657   ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4658   ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4659   dm->fields[f].label = label;
4660   dm->fields[f].disc  = field;
4661   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4662   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4663   ierr = DMSetDefaultAdjacency_Private(dm, f, field);CHKERRQ(ierr);
4664   ierr = DMClearDS(dm);CHKERRQ(ierr);
4665   PetscFunctionReturn(0);
4666 }
4667 
4668 /*@
4669   DMAddField - Add the discretization object for the given DM field
4670 
4671   Logically collective on dm
4672 
4673   Input Parameters:
4674 + dm    - The DM
4675 . label - The label indicating the support of the field, or NULL for the entire mesh
4676 - field - The discretization object
4677 
4678   Level: intermediate
4679 
4680 .seealso: DMSetField(), DMGetField()
4681 @*/
4682 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4683 {
4684   PetscInt       Nf = dm->Nf;
4685   PetscErrorCode ierr;
4686 
4687   PetscFunctionBegin;
4688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4689   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4690   PetscValidHeader(field, 3);
4691   ierr = DMFieldEnlarge_Static(dm, Nf+1);CHKERRQ(ierr);
4692   dm->fields[Nf].label = label;
4693   dm->fields[Nf].disc  = field;
4694   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4695   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4696   ierr = DMSetDefaultAdjacency_Private(dm, Nf, field);CHKERRQ(ierr);
4697   ierr = DMClearDS(dm);CHKERRQ(ierr);
4698   PetscFunctionReturn(0);
4699 }
4700 
4701 /*@
4702   DMCopyFields - Copy the discretizations for the DM into another DM
4703 
4704   Collective on dm
4705 
4706   Input Parameter:
4707 . dm - The DM
4708 
4709   Output Parameter:
4710 . newdm - The DM
4711 
4712   Level: advanced
4713 
4714 .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4715 @*/
4716 PetscErrorCode DMCopyFields(DM dm, DM newdm)
4717 {
4718   PetscInt       Nf, f;
4719   PetscErrorCode ierr;
4720 
4721   PetscFunctionBegin;
4722   if (dm == newdm) PetscFunctionReturn(0);
4723   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4724   ierr = DMClearFields(newdm);CHKERRQ(ierr);
4725   for (f = 0; f < Nf; ++f) {
4726     DMLabel     label;
4727     PetscObject field;
4728     PetscBool   useCone, useClosure;
4729 
4730     ierr = DMGetField(dm, f, &label, &field);CHKERRQ(ierr);
4731     ierr = DMSetField(newdm, f, label, field);CHKERRQ(ierr);
4732     ierr = DMGetAdjacency(dm, f, &useCone, &useClosure);CHKERRQ(ierr);
4733     ierr = DMSetAdjacency(newdm, f, useCone, useClosure);CHKERRQ(ierr);
4734   }
4735   PetscFunctionReturn(0);
4736 }
4737 
4738 /*@
4739   DMGetAdjacency - Returns the flags for determining variable influence
4740 
4741   Not collective
4742 
4743   Input Parameters:
4744 + dm - The DM object
4745 - f  - The field number, or PETSC_DEFAULT for the default adjacency
4746 
4747   Output Parameter:
4748 + useCone    - Flag for variable influence starting with the cone operation
4749 - useClosure - Flag for variable influence using transitive closure
4750 
4751   Notes:
4752 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4753 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4754 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4755   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4756 
4757   Level: developer
4758 
4759 .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4760 @*/
4761 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4762 {
4763   PetscFunctionBegin;
4764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4765   if (useCone)    PetscValidBoolPointer(useCone, 3);
4766   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4767   if (f < 0) {
4768     if (useCone)    *useCone    = dm->adjacency[0];
4769     if (useClosure) *useClosure = dm->adjacency[1];
4770   } else {
4771     PetscInt       Nf;
4772     PetscErrorCode ierr;
4773 
4774     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4775     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4776     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4777     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4778   }
4779   PetscFunctionReturn(0);
4780 }
4781 
4782 /*@
4783   DMSetAdjacency - Set the flags for determining variable influence
4784 
4785   Not collective
4786 
4787   Input Parameters:
4788 + dm         - The DM object
4789 . f          - The field number
4790 . useCone    - Flag for variable influence starting with the cone operation
4791 - useClosure - Flag for variable influence using transitive closure
4792 
4793   Notes:
4794 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4795 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4796 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4797   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4798 
4799   Level: developer
4800 
4801 .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4802 @*/
4803 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4804 {
4805   PetscFunctionBegin;
4806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4807   if (f < 0) {
4808     dm->adjacency[0] = useCone;
4809     dm->adjacency[1] = useClosure;
4810   } else {
4811     PetscInt       Nf;
4812     PetscErrorCode ierr;
4813 
4814     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4815     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4816     dm->fields[f].adjacency[0] = useCone;
4817     dm->fields[f].adjacency[1] = useClosure;
4818   }
4819   PetscFunctionReturn(0);
4820 }
4821 
4822 /*@
4823   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4824 
4825   Not collective
4826 
4827   Input Parameters:
4828 . dm - The DM object
4829 
4830   Output Parameter:
4831 + useCone    - Flag for variable influence starting with the cone operation
4832 - useClosure - Flag for variable influence using transitive closure
4833 
4834   Notes:
4835 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4836 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4837 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4838 
4839   Level: developer
4840 
4841 .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4842 @*/
4843 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4844 {
4845   PetscInt       Nf;
4846   PetscErrorCode ierr;
4847 
4848   PetscFunctionBegin;
4849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4850   if (useCone)    PetscValidBoolPointer(useCone, 3);
4851   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4852   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4853   if (!Nf) {
4854     ierr = DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4855   } else {
4856     ierr = DMGetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4857   }
4858   PetscFunctionReturn(0);
4859 }
4860 
4861 /*@
4862   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
4863 
4864   Not collective
4865 
4866   Input Parameters:
4867 + dm         - The DM object
4868 . useCone    - Flag for variable influence starting with the cone operation
4869 - useClosure - Flag for variable influence using transitive closure
4870 
4871   Notes:
4872 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4873 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4874 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4875 
4876   Level: developer
4877 
4878 .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
4879 @*/
4880 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
4881 {
4882   PetscInt       Nf;
4883   PetscErrorCode ierr;
4884 
4885   PetscFunctionBegin;
4886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4887   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4888   if (!Nf) {
4889     ierr = DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4890   } else {
4891     ierr = DMSetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4892   }
4893   PetscFunctionReturn(0);
4894 }
4895 
4896 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4897 {
4898   DMSpace       *tmpd;
4899   PetscInt       Nds = dm->Nds, s;
4900   PetscErrorCode ierr;
4901 
4902   PetscFunctionBegin;
4903   if (Nds >= NdsNew) PetscFunctionReturn(0);
4904   ierr = PetscMalloc1(NdsNew, &tmpd);CHKERRQ(ierr);
4905   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4906   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
4907   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4908   dm->Nds   = NdsNew;
4909   dm->probs = tmpd;
4910   PetscFunctionReturn(0);
4911 }
4912 
4913 /*@
4914   DMGetNumDS - Get the number of discrete systems in the DM
4915 
4916   Not collective
4917 
4918   Input Parameter:
4919 . dm - The DM
4920 
4921   Output Parameter:
4922 . Nds - The number of PetscDS objects
4923 
4924   Level: intermediate
4925 
4926 .seealso: DMGetDS(), DMGetCellDS()
4927 @*/
4928 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4929 {
4930   PetscFunctionBegin;
4931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4932   PetscValidIntPointer(Nds, 2);
4933   *Nds = dm->Nds;
4934   PetscFunctionReturn(0);
4935 }
4936 
4937 /*@
4938   DMClearDS - Remove all discrete systems from the DM
4939 
4940   Logically collective on dm
4941 
4942   Input Parameter:
4943 . dm - The DM
4944 
4945   Level: intermediate
4946 
4947 .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
4948 @*/
4949 PetscErrorCode DMClearDS(DM dm)
4950 {
4951   PetscInt       s;
4952   PetscErrorCode ierr;
4953 
4954   PetscFunctionBegin;
4955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4956   for (s = 0; s < dm->Nds; ++s) {
4957     ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
4958     ierr = DMLabelDestroy(&dm->probs[s].label);CHKERRQ(ierr);
4959     ierr = ISDestroy(&dm->probs[s].fields);CHKERRQ(ierr);
4960   }
4961   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4962   dm->probs = NULL;
4963   dm->Nds   = 0;
4964   PetscFunctionReturn(0);
4965 }
4966 
4967 /*@
4968   DMGetDS - Get the default PetscDS
4969 
4970   Not collective
4971 
4972   Input Parameter:
4973 . dm    - The DM
4974 
4975   Output Parameter:
4976 . prob - The default PetscDS
4977 
4978   Level: intermediate
4979 
4980 .seealso: DMGetCellDS(), DMGetRegionDS()
4981 @*/
4982 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4983 {
4984   PetscErrorCode ierr;
4985 
4986   PetscFunctionBeginHot;
4987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4988   PetscValidPointer(prob, 2);
4989   if (dm->Nds <= 0) {
4990     PetscDS ds;
4991 
4992     ierr = PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);CHKERRQ(ierr);
4993     ierr = DMSetRegionDS(dm, NULL, NULL, ds);CHKERRQ(ierr);
4994     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
4995   }
4996   *prob = dm->probs[0].ds;
4997   PetscFunctionReturn(0);
4998 }
4999 
5000 /*@
5001   DMGetCellDS - Get the PetscDS defined on a given cell
5002 
5003   Not collective
5004 
5005   Input Parameters:
5006 + dm    - The DM
5007 - point - Cell for the DS
5008 
5009   Output Parameter:
5010 . prob - The PetscDS defined on the given cell
5011 
5012   Level: developer
5013 
5014 .seealso: DMGetDS(), DMSetRegionDS()
5015 @*/
5016 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5017 {
5018   PetscDS        probDef = NULL;
5019   PetscInt       s;
5020   PetscErrorCode ierr;
5021 
5022   PetscFunctionBeginHot;
5023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5024   PetscValidPointer(prob, 3);
5025   *prob = NULL;
5026   for (s = 0; s < dm->Nds; ++s) {
5027     PetscInt val;
5028 
5029     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5030     else {
5031       ierr = DMLabelGetValue(dm->probs[s].label, point, &val);CHKERRQ(ierr);
5032       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5033     }
5034   }
5035   if (!*prob) *prob = probDef;
5036   PetscFunctionReturn(0);
5037 }
5038 
5039 /*@
5040   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5041 
5042   Not collective
5043 
5044   Input Parameters:
5045 + dm    - The DM
5046 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5047 
5048   Output Parameters:
5049 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5050 - prob - The PetscDS defined on the given region, or NULL
5051 
5052   Note: If the label is missing, this function returns an error
5053 
5054   Level: advanced
5055 
5056 .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5057 @*/
5058 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5059 {
5060   PetscInt Nds = dm->Nds, s;
5061 
5062   PetscFunctionBegin;
5063   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5064   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5065   if (fields) {PetscValidPointer(fields, 3); *fields = NULL;}
5066   if (ds)     {PetscValidPointer(ds, 4);     *ds     = NULL;}
5067   for (s = 0; s < Nds; ++s) {
5068     if (dm->probs[s].label == label) {
5069       if (fields) *fields = dm->probs[s].fields;
5070       if (ds)     *ds     = dm->probs[s].ds;
5071       PetscFunctionReturn(0);
5072     }
5073   }
5074   PetscFunctionReturn(0);
5075 }
5076 
5077 /*@
5078   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5079 
5080   Not collective
5081 
5082   Input Parameters:
5083 + dm  - The DM
5084 - num - The region number, in [0, Nds)
5085 
5086   Output Parameters:
5087 + label  - The region label, or NULL
5088 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5089 - prob   - The PetscDS defined on the given region, or NULL
5090 
5091   Level: advanced
5092 
5093 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5094 @*/
5095 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5096 {
5097   PetscInt       Nds;
5098   PetscErrorCode ierr;
5099 
5100   PetscFunctionBegin;
5101   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5102   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5103   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5104   if (label) {
5105     PetscValidPointer(label, 3);
5106     *label = dm->probs[num].label;
5107   }
5108   if (fields) {
5109     PetscValidPointer(fields, 4);
5110     *fields = dm->probs[num].fields;
5111   }
5112   if (ds) {
5113     PetscValidPointer(ds, 5);
5114     *ds = dm->probs[num].ds;
5115   }
5116   PetscFunctionReturn(0);
5117 }
5118 
5119 /*@
5120   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5121 
5122   Collective on dm
5123 
5124   Input Parameters:
5125 + dm     - The DM
5126 . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5127 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5128 - prob   - The PetscDS defined on the given cell
5129 
5130   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5131   the fields argument is ignored.
5132 
5133   Level: advanced
5134 
5135 .seealso: DMGetRegionDS(), DMGetDS(), DMGetCellDS()
5136 @*/
5137 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5138 {
5139   PetscInt       Nds = dm->Nds, s;
5140   PetscErrorCode ierr;
5141 
5142   PetscFunctionBegin;
5143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5144   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5145   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 3);
5146   for (s = 0; s < Nds; ++s) {
5147     if (dm->probs[s].label == label) {
5148       ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
5149       dm->probs[s].ds = ds;
5150       PetscFunctionReturn(0);
5151     }
5152   }
5153   ierr = DMDSEnlarge_Static(dm, Nds+1);CHKERRQ(ierr);
5154   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
5155   ierr = PetscObjectReference((PetscObject) fields);CHKERRQ(ierr);
5156   ierr = PetscObjectReference((PetscObject) ds);CHKERRQ(ierr);
5157   if (!label) {
5158     /* Put the NULL label at the front, so it is returned as the default */
5159     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5160     Nds = 0;
5161   }
5162   dm->probs[Nds].label  = label;
5163   dm->probs[Nds].fields = fields;
5164   dm->probs[Nds].ds     = ds;
5165   PetscFunctionReturn(0);
5166 }
5167 
5168 /*@
5169   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5170 
5171   Collective on dm
5172 
5173   Input Parameter:
5174 . dm - The DM
5175 
5176   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5177 
5178   Level: intermediate
5179 
5180 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5181 @*/
5182 PetscErrorCode DMCreateDS(DM dm)
5183 {
5184   MPI_Comm       comm;
5185   PetscDS        prob, probh = NULL;
5186   PetscInt       dimEmbed, Nf = dm->Nf, f, s, field = 0, fieldh = 0;
5187   PetscBool      doSetup = PETSC_TRUE;
5188   PetscErrorCode ierr;
5189 
5190   PetscFunctionBegin;
5191   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5192   if (!dm->fields) PetscFunctionReturn(0);
5193   /* Can only handle two label cases right now:
5194    1) NULL
5195    2) Hybrid cells
5196   */
5197   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
5198   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
5199   /* Create default DS */
5200   ierr = DMGetRegionDS(dm, NULL, NULL, &prob);CHKERRQ(ierr);
5201   if (!prob) {
5202     IS        fields;
5203     PetscInt *fld, nf;
5204 
5205     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5206     ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5207     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5208     ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5209     ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5210     ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5211     ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5212 
5213     ierr = PetscDSCreate(comm, &prob);CHKERRQ(ierr);
5214     ierr = DMSetRegionDS(dm, NULL, fields, prob);CHKERRQ(ierr);
5215     ierr = PetscDSDestroy(&prob);CHKERRQ(ierr);
5216     ierr = ISDestroy(&fields);CHKERRQ(ierr);
5217     ierr = DMGetRegionDS(dm, NULL, NULL, &prob);CHKERRQ(ierr);
5218   }
5219   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
5220   /* Optionally create hybrid DS */
5221   for (f = 0; f < Nf; ++f) {
5222     DMLabel  label = dm->fields[f].label;
5223     PetscInt lStart, lEnd;
5224 
5225     if (label) {
5226       DM        plex;
5227       IS        fields;
5228       PetscInt *fld;
5229       PetscInt  depth, pMax[4];
5230 
5231       ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
5232       ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
5233       ierr = DMPlexGetHybridBounds(plex, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
5234       ierr = DMDestroy(&plex);CHKERRQ(ierr);
5235 
5236       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
5237       if (lStart < pMax[depth]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over hybrid cells right now");
5238       ierr = PetscDSCreate(comm, &probh);CHKERRQ(ierr);
5239       ierr = PetscMalloc1(1, &fld);CHKERRQ(ierr);
5240       fld[0] = f;
5241       ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5242       ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5243       ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5244       ierr = ISGeneralSetIndices(fields, 1, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5245       ierr = DMSetRegionDS(dm, label, fields, probh);CHKERRQ(ierr);
5246       ierr = ISDestroy(&fields);CHKERRQ(ierr);
5247       ierr = PetscDSSetHybrid(probh, PETSC_TRUE);CHKERRQ(ierr);
5248       ierr = PetscDSSetCoordinateDimension(probh, dimEmbed);CHKERRQ(ierr);
5249       break;
5250     }
5251   }
5252   /* Set fields in DSes */
5253   for (f = 0; f < Nf; ++f) {
5254     DMLabel     label = dm->fields[f].label;
5255     PetscObject disc  = dm->fields[f].disc;
5256 
5257     if (!label) {
5258       ierr = PetscDSSetDiscretization(prob,  field++,  disc);CHKERRQ(ierr);
5259       if (probh) {
5260         PetscFE subfe;
5261 
5262         ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);CHKERRQ(ierr);
5263         ierr = PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);CHKERRQ(ierr);
5264       }
5265     } else {
5266       ierr = PetscDSSetDiscretization(probh, fieldh++, disc);CHKERRQ(ierr);
5267     }
5268     /* We allow people to have placeholder fields and construct the Section by hand */
5269     {
5270       PetscClassId id;
5271 
5272       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
5273       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5274     }
5275   }
5276   ierr = PetscDSDestroy(&probh);CHKERRQ(ierr);
5277   /* Setup DSes */
5278   if (doSetup) {
5279     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
5280   }
5281   PetscFunctionReturn(0);
5282 }
5283 
5284 /*@
5285   DMCopyDS - Copy the discrete systems for the DM into another DM
5286 
5287   Collective on dm
5288 
5289   Input Parameter:
5290 . dm - The DM
5291 
5292   Output Parameter:
5293 . newdm - The DM
5294 
5295   Level: advanced
5296 
5297 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5298 @*/
5299 PetscErrorCode DMCopyDS(DM dm, DM newdm)
5300 {
5301   PetscInt       Nds, s;
5302   PetscErrorCode ierr;
5303 
5304   PetscFunctionBegin;
5305   if (dm == newdm) PetscFunctionReturn(0);
5306   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5307   ierr = DMClearDS(newdm);CHKERRQ(ierr);
5308   for (s = 0; s < Nds; ++s) {
5309     DMLabel label;
5310     IS      fields;
5311     PetscDS ds;
5312 
5313     ierr = DMGetRegionNumDS(dm, s, &label, &fields, &ds);CHKERRQ(ierr);
5314     ierr = DMSetRegionDS(newdm, label, fields, ds);CHKERRQ(ierr);
5315   }
5316   PetscFunctionReturn(0);
5317 }
5318 
5319 /*@
5320   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5321 
5322   Collective on dm
5323 
5324   Input Parameter:
5325 . dm - The DM
5326 
5327   Output Parameter:
5328 . newdm - The DM
5329 
5330   Level: advanced
5331 
5332 .seealso: DMCopyFields(), DMCopyDS()
5333 @*/
5334 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5335 {
5336   PetscErrorCode ierr;
5337 
5338   PetscFunctionBegin;
5339   if (dm == newdm) PetscFunctionReturn(0);
5340   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
5341   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
5342   PetscFunctionReturn(0);
5343 }
5344 
5345 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5346 {
5347   DM dm_coord,dmc_coord;
5348   PetscErrorCode ierr;
5349   Vec coords,ccoords;
5350   Mat inject;
5351   PetscFunctionBegin;
5352   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5353   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5354   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5355   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5356   if (coords && !ccoords) {
5357     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5358     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5359     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5360     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5361     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5362     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5363     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5364   }
5365   PetscFunctionReturn(0);
5366 }
5367 
5368 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5369 {
5370   DM dm_coord,subdm_coord;
5371   PetscErrorCode ierr;
5372   Vec coords,ccoords,clcoords;
5373   VecScatter *scat_i,*scat_g;
5374   PetscFunctionBegin;
5375   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5376   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5377   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5378   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5379   if (coords && !ccoords) {
5380     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5381     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5382     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5383     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5384     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5385     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5386     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5387     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5388     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5389     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5390     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5391     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5392     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5393     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5394     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5395     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5396     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5397   }
5398   PetscFunctionReturn(0);
5399 }
5400 
5401 /*@
5402   DMGetDimension - Return the topological dimension of the DM
5403 
5404   Not collective
5405 
5406   Input Parameter:
5407 . dm - The DM
5408 
5409   Output Parameter:
5410 . dim - The topological dimension
5411 
5412   Level: beginner
5413 
5414 .seealso: DMSetDimension(), DMCreate()
5415 @*/
5416 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5417 {
5418   PetscFunctionBegin;
5419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5420   PetscValidIntPointer(dim, 2);
5421   *dim = dm->dim;
5422   PetscFunctionReturn(0);
5423 }
5424 
5425 /*@
5426   DMSetDimension - Set the topological dimension of the DM
5427 
5428   Collective on dm
5429 
5430   Input Parameters:
5431 + dm - The DM
5432 - dim - The topological dimension
5433 
5434   Level: beginner
5435 
5436 .seealso: DMGetDimension(), DMCreate()
5437 @*/
5438 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5439 {
5440   PetscDS        ds;
5441   PetscErrorCode ierr;
5442 
5443   PetscFunctionBegin;
5444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5445   PetscValidLogicalCollectiveInt(dm, dim, 2);
5446   dm->dim = dim;
5447   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5448   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5449   PetscFunctionReturn(0);
5450 }
5451 
5452 /*@
5453   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5454 
5455   Collective on dm
5456 
5457   Input Parameters:
5458 + dm - the DM
5459 - dim - the dimension
5460 
5461   Output Parameters:
5462 + pStart - The first point of the given dimension
5463 - pEnd - The first point following points of the given dimension
5464 
5465   Note:
5466   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5467   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5468   then the interval is empty.
5469 
5470   Level: intermediate
5471 
5472 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5473 @*/
5474 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5475 {
5476   PetscInt       d;
5477   PetscErrorCode ierr;
5478 
5479   PetscFunctionBegin;
5480   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5481   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5482   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5483   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5484   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5485   PetscFunctionReturn(0);
5486 }
5487 
5488 /*@
5489   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5490 
5491   Collective on dm
5492 
5493   Input Parameters:
5494 + dm - the DM
5495 - c - coordinate vector
5496 
5497   Notes:
5498   The coordinates do include those for ghost points, which are in the local vector.
5499 
5500   The vector c should be destroyed by the caller.
5501 
5502   Level: intermediate
5503 
5504 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5505 @*/
5506 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5507 {
5508   PetscErrorCode ierr;
5509 
5510   PetscFunctionBegin;
5511   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5512   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5513   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5514   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5515   dm->coordinates = c;
5516   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5517   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5518   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5519   PetscFunctionReturn(0);
5520 }
5521 
5522 /*@
5523   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5524 
5525   Not collective
5526 
5527    Input Parameters:
5528 +  dm - the DM
5529 -  c - coordinate vector
5530 
5531   Notes:
5532   The coordinates of ghost points can be set using DMSetCoordinates()
5533   followed by DMGetCoordinatesLocal(). This is intended to enable the
5534   setting of ghost coordinates outside of the domain.
5535 
5536   The vector c should be destroyed by the caller.
5537 
5538   Level: intermediate
5539 
5540 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5541 @*/
5542 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5543 {
5544   PetscErrorCode ierr;
5545 
5546   PetscFunctionBegin;
5547   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5548   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5549   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5550   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5551 
5552   dm->coordinatesLocal = c;
5553 
5554   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5555   PetscFunctionReturn(0);
5556 }
5557 
5558 /*@
5559   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5560 
5561   Collective on dm
5562 
5563   Input Parameter:
5564 . dm - the DM
5565 
5566   Output Parameter:
5567 . c - global coordinate vector
5568 
5569   Note:
5570   This is a borrowed reference, so the user should NOT destroy this vector
5571 
5572   Each process has only the local coordinates (does NOT have the ghost coordinates).
5573 
5574   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5575   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5576 
5577   Level: intermediate
5578 
5579 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5580 @*/
5581 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5582 {
5583   PetscErrorCode ierr;
5584 
5585   PetscFunctionBegin;
5586   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5587   PetscValidPointer(c,2);
5588   if (!dm->coordinates && dm->coordinatesLocal) {
5589     DM        cdm = NULL;
5590     PetscBool localized;
5591 
5592     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5593     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5594     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5595     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5596     if (localized) {
5597       PetscInt cdim;
5598 
5599       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5600       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5601     }
5602     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
5603     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5604     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5605   }
5606   *c = dm->coordinates;
5607   PetscFunctionReturn(0);
5608 }
5609 
5610 /*@
5611   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
5612 
5613   Collective on dm
5614 
5615   Input Parameter:
5616 . dm - the DM
5617 
5618   Level: advanced
5619 
5620 .seealso: DMGetCoordinatesLocalNoncollective()
5621 @*/
5622 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5623 {
5624   PetscErrorCode ierr;
5625 
5626   PetscFunctionBegin;
5627   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5628   if (!dm->coordinatesLocal && dm->coordinates) {
5629     DM        cdm = NULL;
5630     PetscBool localized;
5631 
5632     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5633     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
5634     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5635     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5636     if (localized) {
5637       PetscInt cdim;
5638 
5639       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5640       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5641     }
5642     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
5643     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5644     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5645   }
5646   PetscFunctionReturn(0);
5647 }
5648 
5649 /*@
5650   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
5651 
5652   Collective on dm
5653 
5654   Input Parameter:
5655 . dm - the DM
5656 
5657   Output Parameter:
5658 . c - coordinate vector
5659 
5660   Note:
5661   This is a borrowed reference, so the user should NOT destroy this vector
5662 
5663   Each process has the local and ghost coordinates
5664 
5665   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5666   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5667 
5668   Level: intermediate
5669 
5670 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5671 @*/
5672 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5673 {
5674   PetscErrorCode ierr;
5675 
5676   PetscFunctionBegin;
5677   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5678   PetscValidPointer(c,2);
5679   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
5680   *c = dm->coordinatesLocal;
5681   PetscFunctionReturn(0);
5682 }
5683 
5684 /*@
5685   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
5686 
5687   Not collective
5688 
5689   Input Parameter:
5690 . dm - the DM
5691 
5692   Output Parameter:
5693 . c - coordinate vector
5694 
5695   Level: advanced
5696 
5697 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5698 @*/
5699 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5700 {
5701   PetscFunctionBegin;
5702   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5703   PetscValidPointer(c,2);
5704   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5705   *c = dm->coordinatesLocal;
5706   PetscFunctionReturn(0);
5707 }
5708 
5709 /*@
5710   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
5711 
5712   Not collective
5713 
5714   Input Parameter:
5715 + dm - the DM
5716 - p - the IS of points whose coordinates will be returned
5717 
5718   Output Parameter:
5719 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5720 - pCoord - the Vec with coordinates of points in p
5721 
5722   Note:
5723   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
5724 
5725   This creates a new vector, so the user SHOULD destroy this vector
5726 
5727   Each process has the local and ghost coordinates
5728 
5729   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5730   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5731 
5732   Level: advanced
5733 
5734 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5735 @*/
5736 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5737 {
5738   PetscSection        cs, newcs;
5739   Vec                 coords;
5740   const PetscScalar   *arr;
5741   PetscScalar         *newarr=NULL;
5742   PetscInt            n;
5743   PetscErrorCode      ierr;
5744 
5745   PetscFunctionBegin;
5746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5747   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
5748   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
5749   if (pCoord) PetscValidPointer(pCoord, 4);
5750   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5751   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5752   cs = dm->coordinateDM->localSection;
5753   coords = dm->coordinatesLocal;
5754   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
5755   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
5756   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
5757   if (pCoord) {
5758     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
5759     /* set array in two steps to mimic PETSC_OWN_POINTER */
5760     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
5761     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
5762   } else {
5763     ierr = PetscFree(newarr);CHKERRQ(ierr);
5764   }
5765   if (pCoordSection) {*pCoordSection = newcs;}
5766   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
5767   PetscFunctionReturn(0);
5768 }
5769 
5770 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5771 {
5772   PetscErrorCode ierr;
5773 
5774   PetscFunctionBegin;
5775   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5776   PetscValidPointer(field,2);
5777   if (!dm->coordinateField) {
5778     if (dm->ops->createcoordinatefield) {
5779       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
5780     }
5781   }
5782   *field = dm->coordinateField;
5783   PetscFunctionReturn(0);
5784 }
5785 
5786 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5787 {
5788   PetscErrorCode ierr;
5789 
5790   PetscFunctionBegin;
5791   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5792   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
5793   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
5794   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
5795   dm->coordinateField = field;
5796   PetscFunctionReturn(0);
5797 }
5798 
5799 /*@
5800   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
5801 
5802   Collective on dm
5803 
5804   Input Parameter:
5805 . dm - the DM
5806 
5807   Output Parameter:
5808 . cdm - coordinate DM
5809 
5810   Level: intermediate
5811 
5812 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5813 @*/
5814 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5815 {
5816   PetscErrorCode ierr;
5817 
5818   PetscFunctionBegin;
5819   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5820   PetscValidPointer(cdm,2);
5821   if (!dm->coordinateDM) {
5822     DM cdm;
5823 
5824     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5825     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
5826     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5827      * until the call to CreateCoordinateDM) */
5828     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5829     dm->coordinateDM = cdm;
5830   }
5831   *cdm = dm->coordinateDM;
5832   PetscFunctionReturn(0);
5833 }
5834 
5835 /*@
5836   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
5837 
5838   Logically Collective on dm
5839 
5840   Input Parameters:
5841 + dm - the DM
5842 - cdm - coordinate DM
5843 
5844   Level: intermediate
5845 
5846 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5847 @*/
5848 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5849 {
5850   PetscErrorCode ierr;
5851 
5852   PetscFunctionBegin;
5853   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5854   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
5855   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5856   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5857   dm->coordinateDM = cdm;
5858   PetscFunctionReturn(0);
5859 }
5860 
5861 /*@
5862   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
5863 
5864   Not Collective
5865 
5866   Input Parameter:
5867 . dm - The DM object
5868 
5869   Output Parameter:
5870 . dim - The embedding dimension
5871 
5872   Level: intermediate
5873 
5874 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5875 @*/
5876 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5877 {
5878   PetscFunctionBegin;
5879   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5880   PetscValidIntPointer(dim, 2);
5881   if (dm->dimEmbed == PETSC_DEFAULT) {
5882     dm->dimEmbed = dm->dim;
5883   }
5884   *dim = dm->dimEmbed;
5885   PetscFunctionReturn(0);
5886 }
5887 
5888 /*@
5889   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
5890 
5891   Not Collective
5892 
5893   Input Parameters:
5894 + dm  - The DM object
5895 - dim - The embedding dimension
5896 
5897   Level: intermediate
5898 
5899 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5900 @*/
5901 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5902 {
5903   PetscDS        ds;
5904   PetscErrorCode ierr;
5905 
5906   PetscFunctionBegin;
5907   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5908   dm->dimEmbed = dim;
5909   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5910   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
5911   PetscFunctionReturn(0);
5912 }
5913 
5914 /*@
5915   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
5916 
5917   Collective on dm
5918 
5919   Input Parameter:
5920 . dm - The DM object
5921 
5922   Output Parameter:
5923 . section - The PetscSection object
5924 
5925   Level: intermediate
5926 
5927 .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5928 @*/
5929 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5930 {
5931   DM             cdm;
5932   PetscErrorCode ierr;
5933 
5934   PetscFunctionBegin;
5935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5936   PetscValidPointer(section, 2);
5937   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5938   ierr = DMGetLocalSection(cdm, section);CHKERRQ(ierr);
5939   PetscFunctionReturn(0);
5940 }
5941 
5942 /*@
5943   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
5944 
5945   Not Collective
5946 
5947   Input Parameters:
5948 + dm      - The DM object
5949 . dim     - The embedding dimension, or PETSC_DETERMINE
5950 - section - The PetscSection object
5951 
5952   Level: intermediate
5953 
5954 .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5955 @*/
5956 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5957 {
5958   DM             cdm;
5959   PetscErrorCode ierr;
5960 
5961   PetscFunctionBegin;
5962   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5963   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
5964   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5965   ierr = DMSetLocalSection(cdm, section);CHKERRQ(ierr);
5966   if (dim == PETSC_DETERMINE) {
5967     PetscInt d = PETSC_DEFAULT;
5968     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
5969 
5970     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5971     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5972     pStart = PetscMax(vStart, pStart);
5973     pEnd   = PetscMin(vEnd, pEnd);
5974     for (v = pStart; v < pEnd; ++v) {
5975       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
5976       if (dd) {d = dd; break;}
5977     }
5978     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
5979   }
5980   PetscFunctionReturn(0);
5981 }
5982 
5983 /*@C
5984   DMGetPeriodicity - Get the description of mesh periodicity
5985 
5986   Input Parameters:
5987 . dm      - The DM object
5988 
5989   Output Parameters:
5990 + per     - Whether the DM is periodic or not
5991 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5992 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5993 - bd      - This describes the type of periodicity in each topological dimension
5994 
5995   Level: developer
5996 
5997 .seealso: DMGetPeriodicity()
5998 @*/
5999 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6000 {
6001   PetscFunctionBegin;
6002   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6003   if (per)     *per     = dm->periodic;
6004   if (L)       *L       = dm->L;
6005   if (maxCell) *maxCell = dm->maxCell;
6006   if (bd)      *bd      = dm->bdtype;
6007   PetscFunctionReturn(0);
6008 }
6009 
6010 /*@C
6011   DMSetPeriodicity - Set the description of mesh periodicity
6012 
6013   Input Parameters:
6014 + dm      - The DM object
6015 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6016 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6017 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6018 - bd      - This describes the type of periodicity in each topological dimension
6019 
6020   Level: developer
6021 
6022 .seealso: DMGetPeriodicity()
6023 @*/
6024 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6025 {
6026   PetscInt       dim, d;
6027   PetscErrorCode ierr;
6028 
6029   PetscFunctionBegin;
6030   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6031   PetscValidLogicalCollectiveBool(dm,per,2);
6032   if (maxCell) {
6033     PetscValidRealPointer(maxCell,3);
6034     PetscValidRealPointer(L,4);
6035     PetscValidPointer(bd,5);
6036   }
6037   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
6038   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6039   if (maxCell) {
6040     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
6041     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
6042   }
6043   dm->periodic = per;
6044   PetscFunctionReturn(0);
6045 }
6046 
6047 /*@
6048   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.
6049 
6050   Input Parameters:
6051 + dm     - The DM
6052 . in     - The input coordinate point (dim numbers)
6053 - endpoint - Include the endpoint L_i
6054 
6055   Output Parameter:
6056 . out - The localized coordinate point
6057 
6058   Level: developer
6059 
6060 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6061 @*/
6062 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6063 {
6064   PetscInt       dim, d;
6065   PetscErrorCode ierr;
6066 
6067   PetscFunctionBegin;
6068   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
6069   if (!dm->maxCell) {
6070     for (d = 0; d < dim; ++d) out[d] = in[d];
6071   } else {
6072     if (endpoint) {
6073       for (d = 0; d < dim; ++d) {
6074         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)) {
6075           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6076         } else {
6077           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6078         }
6079       }
6080     } else {
6081       for (d = 0; d < dim; ++d) {
6082         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6083       }
6084     }
6085   }
6086   PetscFunctionReturn(0);
6087 }
6088 
6089 /*
6090   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.
6091 
6092   Input Parameters:
6093 + dm     - The DM
6094 . dim    - The spatial dimension
6095 . anchor - The anchor point, the input point can be no more than maxCell away from it
6096 - in     - The input coordinate point (dim numbers)
6097 
6098   Output Parameter:
6099 . out - The localized coordinate point
6100 
6101   Level: developer
6102 
6103   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
6104 
6105 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6106 */
6107 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6108 {
6109   PetscInt d;
6110 
6111   PetscFunctionBegin;
6112   if (!dm->maxCell) {
6113     for (d = 0; d < dim; ++d) out[d] = in[d];
6114   } else {
6115     for (d = 0; d < dim; ++d) {
6116       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6117         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6118       } else {
6119         out[d] = in[d];
6120       }
6121     }
6122   }
6123   PetscFunctionReturn(0);
6124 }
6125 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6126 {
6127   PetscInt d;
6128 
6129   PetscFunctionBegin;
6130   if (!dm->maxCell) {
6131     for (d = 0; d < dim; ++d) out[d] = in[d];
6132   } else {
6133     for (d = 0; d < dim; ++d) {
6134       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6135         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6136       } else {
6137         out[d] = in[d];
6138       }
6139     }
6140   }
6141   PetscFunctionReturn(0);
6142 }
6143 
6144 /*
6145   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.
6146 
6147   Input Parameters:
6148 + dm     - The DM
6149 . dim    - The spatial dimension
6150 . anchor - The anchor point, the input point can be no more than maxCell away from it
6151 . in     - The input coordinate delta (dim numbers)
6152 - out    - The input coordinate point (dim numbers)
6153 
6154   Output Parameter:
6155 . out    - The localized coordinate in + out
6156 
6157   Level: developer
6158 
6159   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
6160 
6161 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6162 */
6163 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6164 {
6165   PetscInt d;
6166 
6167   PetscFunctionBegin;
6168   if (!dm->maxCell) {
6169     for (d = 0; d < dim; ++d) out[d] += in[d];
6170   } else {
6171     for (d = 0; d < dim; ++d) {
6172       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6173         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6174       } else {
6175         out[d] += in[d];
6176       }
6177     }
6178   }
6179   PetscFunctionReturn(0);
6180 }
6181 
6182 /*@
6183   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6184 
6185   Not collective
6186 
6187   Input Parameter:
6188 . dm - The DM
6189 
6190   Output Parameter:
6191   areLocalized - True if localized
6192 
6193   Level: developer
6194 
6195 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6196 @*/
6197 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6198 {
6199   DM             cdm;
6200   PetscSection   coordSection;
6201   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6202   PetscBool      isPlex, alreadyLocalized;
6203   PetscErrorCode ierr;
6204 
6205   PetscFunctionBegin;
6206   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6207   PetscValidBoolPointer(areLocalized, 2);
6208   *areLocalized = PETSC_FALSE;
6209 
6210   /* We need some generic way of refering to cells/vertices */
6211   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6212   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6213   if (!isPlex) PetscFunctionReturn(0);
6214 
6215   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6216   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6217   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6218   alreadyLocalized = PETSC_FALSE;
6219   for (c = cStart; c < cEnd; ++c) {
6220     if (c < sStart || c >= sEnd) continue;
6221     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6222     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6223   }
6224   *areLocalized = alreadyLocalized;
6225   PetscFunctionReturn(0);
6226 }
6227 
6228 /*@
6229   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6230 
6231   Collective on dm
6232 
6233   Input Parameter:
6234 . dm - The DM
6235 
6236   Output Parameter:
6237   areLocalized - True if localized
6238 
6239   Level: developer
6240 
6241 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6242 @*/
6243 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6244 {
6245   PetscBool      localized;
6246   PetscErrorCode ierr;
6247 
6248   PetscFunctionBegin;
6249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6250   PetscValidBoolPointer(areLocalized, 2);
6251   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6252   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6253   PetscFunctionReturn(0);
6254 }
6255 
6256 /*@
6257   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6258 
6259   Collective on dm
6260 
6261   Input Parameter:
6262 . dm - The DM
6263 
6264   Level: developer
6265 
6266 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6267 @*/
6268 PetscErrorCode DMLocalizeCoordinates(DM dm)
6269 {
6270   DM             cdm;
6271   PetscSection   coordSection, cSection;
6272   Vec            coordinates,  cVec;
6273   PetscScalar   *coords, *coords2, *anchor, *localized;
6274   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6275   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6276   PetscInt       maxHeight = 0, h;
6277   PetscInt       *pStart = NULL, *pEnd = NULL;
6278   PetscErrorCode ierr;
6279 
6280   PetscFunctionBegin;
6281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6282   if (!dm->periodic) PetscFunctionReturn(0);
6283   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6284   if (alreadyLocalized) PetscFunctionReturn(0);
6285 
6286   /* We need some generic way of refering to cells/vertices */
6287   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6288   {
6289     PetscBool isplex;
6290 
6291     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6292     if (isplex) {
6293       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6294       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6295       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6296       pEnd = &pStart[maxHeight + 1];
6297       newStart = vStart;
6298       newEnd   = vEnd;
6299       for (h = 0; h <= maxHeight; h++) {
6300         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6301         newStart = PetscMin(newStart,pStart[h]);
6302         newEnd   = PetscMax(newEnd,pEnd[h]);
6303       }
6304     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6305   }
6306   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6307   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6308   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6309   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6310   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6311 
6312   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6313   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6314   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6315   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6316   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6317 
6318   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6319   localized = &anchor[bs];
6320   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6321   for (h = 0; h <= maxHeight; h++) {
6322     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6323 
6324     for (c = cStart; c < cEnd; ++c) {
6325       PetscScalar *cellCoords = NULL;
6326       PetscInt     b;
6327 
6328       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6329       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6330       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6331       for (d = 0; d < dof/bs; ++d) {
6332         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6333         for (b = 0; b < bs; b++) {
6334           if (cellCoords[d*bs + b] != localized[b]) break;
6335         }
6336         if (b < bs) break;
6337       }
6338       if (d < dof/bs) {
6339         if (c >= sStart && c < sEnd) {
6340           PetscInt cdof;
6341 
6342           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6343           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6344         }
6345         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6346         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6347       }
6348       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6349     }
6350   }
6351   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6352   if (alreadyLocalizedGlobal) {
6353     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6354     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6355     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6356     PetscFunctionReturn(0);
6357   }
6358   for (v = vStart; v < vEnd; ++v) {
6359     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6360     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6361     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6362   }
6363   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6364   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6365   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6366   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6367   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6368   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6369   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6370   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6371   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6372   for (v = vStart; v < vEnd; ++v) {
6373     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6374     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6375     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6376     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6377   }
6378   for (h = 0; h <= maxHeight; h++) {
6379     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6380 
6381     for (c = cStart; c < cEnd; ++c) {
6382       PetscScalar *cellCoords = NULL;
6383       PetscInt     b, cdof;
6384 
6385       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6386       if (!cdof) continue;
6387       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6388       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6389       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6390       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6391       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6392     }
6393   }
6394   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6395   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6396   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6397   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6398   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6399   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6400   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6401   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6402   PetscFunctionReturn(0);
6403 }
6404 
6405 /*@
6406   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6407 
6408   Collective on v (see explanation below)
6409 
6410   Input Parameters:
6411 + dm - The DM
6412 . v - The Vec of points
6413 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6414 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6415 
6416   Output Parameter:
6417 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6418 - cells - The PetscSF containing the ranks and local indices of the containing points.
6419 
6420 
6421   Level: developer
6422 
6423   Notes:
6424   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6425   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6426 
6427   If *cellSF is NULL on input, a PetscSF will be created.
6428   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6429 
6430   An array that maps each point to its containing cell can be obtained with
6431 
6432 $    const PetscSFNode *cells;
6433 $    PetscInt           nFound;
6434 $    const PetscInt    *found;
6435 $
6436 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6437 
6438   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6439   the index of the cell in its rank's local numbering.
6440 
6441 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6442 @*/
6443 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6444 {
6445   PetscErrorCode ierr;
6446 
6447   PetscFunctionBegin;
6448   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6449   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6450   PetscValidPointer(cellSF,4);
6451   if (*cellSF) {
6452     PetscMPIInt result;
6453 
6454     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6455     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6456     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6457   } else {
6458     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6459   }
6460   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6461   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6462   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6463   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6464   PetscFunctionReturn(0);
6465 }
6466 
6467 /*@
6468   DMGetOutputDM - Retrieve the DM associated with the layout for output
6469 
6470   Collective on dm
6471 
6472   Input Parameter:
6473 . dm - The original DM
6474 
6475   Output Parameter:
6476 . odm - The DM which provides the layout for output
6477 
6478   Level: intermediate
6479 
6480 .seealso: VecView(), DMGetGlobalSection()
6481 @*/
6482 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6483 {
6484   PetscSection   section;
6485   PetscBool      hasConstraints, ghasConstraints;
6486   PetscErrorCode ierr;
6487 
6488   PetscFunctionBegin;
6489   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6490   PetscValidPointer(odm,2);
6491   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6492   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6493   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6494   if (!ghasConstraints) {
6495     *odm = dm;
6496     PetscFunctionReturn(0);
6497   }
6498   if (!dm->dmBC) {
6499     PetscSection newSection, gsection;
6500     PetscSF      sf;
6501 
6502     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6503     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6504     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6505     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6506     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6507     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6508     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6509     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6510     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6511   }
6512   *odm = dm->dmBC;
6513   PetscFunctionReturn(0);
6514 }
6515 
6516 /*@
6517   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6518 
6519   Input Parameter:
6520 . dm - The original DM
6521 
6522   Output Parameters:
6523 + num - The output sequence number
6524 - val - The output sequence value
6525 
6526   Level: intermediate
6527 
6528   Note: This is intended for output that should appear in sequence, for instance
6529   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6530 
6531 .seealso: VecView()
6532 @*/
6533 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6534 {
6535   PetscFunctionBegin;
6536   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6537   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
6538   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
6539   PetscFunctionReturn(0);
6540 }
6541 
6542 /*@
6543   DMSetOutputSequenceNumber - Set the sequence number/value for output
6544 
6545   Input Parameters:
6546 + dm - The original DM
6547 . num - The output sequence number
6548 - val - The output sequence value
6549 
6550   Level: intermediate
6551 
6552   Note: This is intended for output that should appear in sequence, for instance
6553   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6554 
6555 .seealso: VecView()
6556 @*/
6557 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6558 {
6559   PetscFunctionBegin;
6560   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6561   dm->outputSequenceNum = num;
6562   dm->outputSequenceVal = val;
6563   PetscFunctionReturn(0);
6564 }
6565 
6566 /*@C
6567   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6568 
6569   Input Parameters:
6570 + dm   - The original DM
6571 . name - The sequence name
6572 - num  - The output sequence number
6573 
6574   Output Parameter:
6575 . val  - The output sequence value
6576 
6577   Level: intermediate
6578 
6579   Note: This is intended for output that should appear in sequence, for instance
6580   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6581 
6582 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6583 @*/
6584 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6585 {
6586   PetscBool      ishdf5;
6587   PetscErrorCode ierr;
6588 
6589   PetscFunctionBegin;
6590   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6591   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6592   PetscValidRealPointer(val,4);
6593   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6594   if (ishdf5) {
6595 #if defined(PETSC_HAVE_HDF5)
6596     PetscScalar value;
6597 
6598     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6599     *val = PetscRealPart(value);
6600 #endif
6601   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6602   PetscFunctionReturn(0);
6603 }
6604 
6605 /*@
6606   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6607 
6608   Not collective
6609 
6610   Input Parameter:
6611 . dm - The DM
6612 
6613   Output Parameter:
6614 . useNatural - The flag to build the mapping to a natural order during distribution
6615 
6616   Level: beginner
6617 
6618 .seealso: DMSetUseNatural(), DMCreate()
6619 @*/
6620 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6621 {
6622   PetscFunctionBegin;
6623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6624   PetscValidBoolPointer(useNatural, 2);
6625   *useNatural = dm->useNatural;
6626   PetscFunctionReturn(0);
6627 }
6628 
6629 /*@
6630   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6631 
6632   Collective on dm
6633 
6634   Input Parameters:
6635 + dm - The DM
6636 - useNatural - The flag to build the mapping to a natural order during distribution
6637 
6638   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6639 
6640   Level: beginner
6641 
6642 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6643 @*/
6644 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6645 {
6646   PetscFunctionBegin;
6647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6648   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6649   dm->useNatural = useNatural;
6650   PetscFunctionReturn(0);
6651 }
6652 
6653 
6654 /*@C
6655   DMCreateLabel - Create a label of the given name if it does not already exist
6656 
6657   Not Collective
6658 
6659   Input Parameters:
6660 + dm   - The DM object
6661 - name - The label name
6662 
6663   Level: intermediate
6664 
6665 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6666 @*/
6667 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6668 {
6669   PetscBool      flg;
6670   DMLabel        label;
6671   PetscErrorCode ierr;
6672 
6673   PetscFunctionBegin;
6674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6675   PetscValidCharPointer(name, 2);
6676   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
6677   if (!flg) {
6678     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
6679     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
6680     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
6681   }
6682   PetscFunctionReturn(0);
6683 }
6684 
6685 /*@C
6686   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6687 
6688   Not Collective
6689 
6690   Input Parameters:
6691 + dm   - The DM object
6692 . name - The label name
6693 - point - The mesh point
6694 
6695   Output Parameter:
6696 . value - The label value for this point, or -1 if the point is not in the label
6697 
6698   Level: beginner
6699 
6700 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6701 @*/
6702 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6703 {
6704   DMLabel        label;
6705   PetscErrorCode ierr;
6706 
6707   PetscFunctionBegin;
6708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6709   PetscValidCharPointer(name, 2);
6710   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6711   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6712   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6713   PetscFunctionReturn(0);
6714 }
6715 
6716 /*@C
6717   DMSetLabelValue - Add a point to a Sieve Label with given value
6718 
6719   Not Collective
6720 
6721   Input Parameters:
6722 + dm   - The DM object
6723 . name - The label name
6724 . point - The mesh point
6725 - value - The label value for this point
6726 
6727   Output Parameter:
6728 
6729   Level: beginner
6730 
6731 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6732 @*/
6733 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6734 {
6735   DMLabel        label;
6736   PetscErrorCode ierr;
6737 
6738   PetscFunctionBegin;
6739   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6740   PetscValidCharPointer(name, 2);
6741   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6742   if (!label) {
6743     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6744     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6745   }
6746   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6747   PetscFunctionReturn(0);
6748 }
6749 
6750 /*@C
6751   DMClearLabelValue - Remove a point from a Sieve Label with given value
6752 
6753   Not Collective
6754 
6755   Input Parameters:
6756 + dm   - The DM object
6757 . name - The label name
6758 . point - The mesh point
6759 - value - The label value for this point
6760 
6761   Output Parameter:
6762 
6763   Level: beginner
6764 
6765 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6766 @*/
6767 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6768 {
6769   DMLabel        label;
6770   PetscErrorCode ierr;
6771 
6772   PetscFunctionBegin;
6773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6774   PetscValidCharPointer(name, 2);
6775   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6776   if (!label) PetscFunctionReturn(0);
6777   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6778   PetscFunctionReturn(0);
6779 }
6780 
6781 /*@C
6782   DMGetLabelSize - Get the number of different integer ids in a Label
6783 
6784   Not Collective
6785 
6786   Input Parameters:
6787 + dm   - The DM object
6788 - name - The label name
6789 
6790   Output Parameter:
6791 . size - The number of different integer ids, or 0 if the label does not exist
6792 
6793   Level: beginner
6794 
6795 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6796 @*/
6797 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6798 {
6799   DMLabel        label;
6800   PetscErrorCode ierr;
6801 
6802   PetscFunctionBegin;
6803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6804   PetscValidCharPointer(name, 2);
6805   PetscValidIntPointer(size, 3);
6806   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6807   *size = 0;
6808   if (!label) PetscFunctionReturn(0);
6809   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
6810   PetscFunctionReturn(0);
6811 }
6812 
6813 /*@C
6814   DMGetLabelIdIS - Get the integer ids in a label
6815 
6816   Not Collective
6817 
6818   Input Parameters:
6819 + mesh - The DM object
6820 - name - The label name
6821 
6822   Output Parameter:
6823 . ids - The integer ids, or NULL if the label does not exist
6824 
6825   Level: beginner
6826 
6827 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6828 @*/
6829 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6830 {
6831   DMLabel        label;
6832   PetscErrorCode ierr;
6833 
6834   PetscFunctionBegin;
6835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6836   PetscValidCharPointer(name, 2);
6837   PetscValidPointer(ids, 3);
6838   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6839   *ids = NULL;
6840  if (label) {
6841     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
6842   } else {
6843     /* returning an empty IS */
6844     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
6845   }
6846   PetscFunctionReturn(0);
6847 }
6848 
6849 /*@C
6850   DMGetStratumSize - Get the number of points in a label stratum
6851 
6852   Not Collective
6853 
6854   Input Parameters:
6855 + dm - The DM object
6856 . name - The label name
6857 - value - The stratum value
6858 
6859   Output Parameter:
6860 . size - The stratum size
6861 
6862   Level: beginner
6863 
6864 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6865 @*/
6866 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6867 {
6868   DMLabel        label;
6869   PetscErrorCode ierr;
6870 
6871   PetscFunctionBegin;
6872   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6873   PetscValidCharPointer(name, 2);
6874   PetscValidIntPointer(size, 4);
6875   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6876   *size = 0;
6877   if (!label) PetscFunctionReturn(0);
6878   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
6879   PetscFunctionReturn(0);
6880 }
6881 
6882 /*@C
6883   DMGetStratumIS - Get the points in a label stratum
6884 
6885   Not Collective
6886 
6887   Input Parameters:
6888 + dm - The DM object
6889 . name - The label name
6890 - value - The stratum value
6891 
6892   Output Parameter:
6893 . points - The stratum points, or NULL if the label does not exist or does not have that value
6894 
6895   Level: beginner
6896 
6897 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6898 @*/
6899 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6900 {
6901   DMLabel        label;
6902   PetscErrorCode ierr;
6903 
6904   PetscFunctionBegin;
6905   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6906   PetscValidCharPointer(name, 2);
6907   PetscValidPointer(points, 4);
6908   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6909   *points = NULL;
6910   if (!label) PetscFunctionReturn(0);
6911   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
6912   PetscFunctionReturn(0);
6913 }
6914 
6915 /*@C
6916   DMSetStratumIS - Set the points in a label stratum
6917 
6918   Not Collective
6919 
6920   Input Parameters:
6921 + dm - The DM object
6922 . name - The label name
6923 . value - The stratum value
6924 - points - The stratum points
6925 
6926   Level: beginner
6927 
6928 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6929 @*/
6930 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6931 {
6932   DMLabel        label;
6933   PetscErrorCode ierr;
6934 
6935   PetscFunctionBegin;
6936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6937   PetscValidCharPointer(name, 2);
6938   PetscValidPointer(points, 4);
6939   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6940   if (!label) PetscFunctionReturn(0);
6941   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
6942   PetscFunctionReturn(0);
6943 }
6944 
6945 /*@C
6946   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
6947 
6948   Not Collective
6949 
6950   Input Parameters:
6951 + dm   - The DM object
6952 . name - The label name
6953 - value - The label value for this point
6954 
6955   Output Parameter:
6956 
6957   Level: beginner
6958 
6959 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6960 @*/
6961 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6962 {
6963   DMLabel        label;
6964   PetscErrorCode ierr;
6965 
6966   PetscFunctionBegin;
6967   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6968   PetscValidCharPointer(name, 2);
6969   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6970   if (!label) PetscFunctionReturn(0);
6971   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
6972   PetscFunctionReturn(0);
6973 }
6974 
6975 /*@
6976   DMGetNumLabels - Return the number of labels defined by the mesh
6977 
6978   Not Collective
6979 
6980   Input Parameter:
6981 . dm   - The DM object
6982 
6983   Output Parameter:
6984 . numLabels - the number of Labels
6985 
6986   Level: intermediate
6987 
6988 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6989 @*/
6990 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6991 {
6992   DMLabelLink next = dm->labels;
6993   PetscInt  n    = 0;
6994 
6995   PetscFunctionBegin;
6996   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6997   PetscValidIntPointer(numLabels, 2);
6998   while (next) {++n; next = next->next;}
6999   *numLabels = n;
7000   PetscFunctionReturn(0);
7001 }
7002 
7003 /*@C
7004   DMGetLabelName - Return the name of nth label
7005 
7006   Not Collective
7007 
7008   Input Parameters:
7009 + dm - The DM object
7010 - n  - the label number
7011 
7012   Output Parameter:
7013 . name - the label name
7014 
7015   Level: intermediate
7016 
7017 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7018 @*/
7019 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7020 {
7021   DMLabelLink    next = dm->labels;
7022   PetscInt       l    = 0;
7023   PetscErrorCode ierr;
7024 
7025   PetscFunctionBegin;
7026   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7027   PetscValidPointer(name, 3);
7028   while (next) {
7029     if (l == n) {
7030       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
7031       PetscFunctionReturn(0);
7032     }
7033     ++l;
7034     next = next->next;
7035   }
7036   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7037 }
7038 
7039 /*@C
7040   DMHasLabel - Determine whether the mesh has a label of a given name
7041 
7042   Not Collective
7043 
7044   Input Parameters:
7045 + dm   - The DM object
7046 - name - The label name
7047 
7048   Output Parameter:
7049 . hasLabel - PETSC_TRUE if the label is present
7050 
7051   Level: intermediate
7052 
7053 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7054 @*/
7055 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7056 {
7057   DMLabelLink    next = dm->labels;
7058   const char    *lname;
7059   PetscErrorCode ierr;
7060 
7061   PetscFunctionBegin;
7062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7063   PetscValidCharPointer(name, 2);
7064   PetscValidBoolPointer(hasLabel, 3);
7065   *hasLabel = PETSC_FALSE;
7066   while (next) {
7067     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7068     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
7069     if (*hasLabel) break;
7070     next = next->next;
7071   }
7072   PetscFunctionReturn(0);
7073 }
7074 
7075 /*@C
7076   DMGetLabel - Return the label of a given name, or NULL
7077 
7078   Not Collective
7079 
7080   Input Parameters:
7081 + dm   - The DM object
7082 - name - The label name
7083 
7084   Output Parameter:
7085 . label - The DMLabel, or NULL if the label is absent
7086 
7087   Level: intermediate
7088 
7089 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7090 @*/
7091 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7092 {
7093   DMLabelLink    next = dm->labels;
7094   PetscBool      hasLabel;
7095   const char    *lname;
7096   PetscErrorCode ierr;
7097 
7098   PetscFunctionBegin;
7099   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7100   PetscValidCharPointer(name, 2);
7101   PetscValidPointer(label, 3);
7102   *label = NULL;
7103   while (next) {
7104     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7105     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7106     if (hasLabel) {
7107       *label = next->label;
7108       break;
7109     }
7110     next = next->next;
7111   }
7112   PetscFunctionReturn(0);
7113 }
7114 
7115 /*@C
7116   DMGetLabelByNum - Return the nth label
7117 
7118   Not Collective
7119 
7120   Input Parameters:
7121 + dm - The DM object
7122 - n  - the label number
7123 
7124   Output Parameter:
7125 . label - the label
7126 
7127   Level: intermediate
7128 
7129 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7130 @*/
7131 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7132 {
7133   DMLabelLink next = dm->labels;
7134   PetscInt    l    = 0;
7135 
7136   PetscFunctionBegin;
7137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7138   PetscValidPointer(label, 3);
7139   while (next) {
7140     if (l == n) {
7141       *label = next->label;
7142       PetscFunctionReturn(0);
7143     }
7144     ++l;
7145     next = next->next;
7146   }
7147   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7148 }
7149 
7150 /*@C
7151   DMAddLabel - Add the label to this mesh
7152 
7153   Not Collective
7154 
7155   Input Parameters:
7156 + dm   - The DM object
7157 - label - The DMLabel
7158 
7159   Level: developer
7160 
7161 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7162 @*/
7163 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7164 {
7165   DMLabelLink    l, *p, tmpLabel;
7166   PetscBool      hasLabel;
7167   const char    *lname;
7168   PetscBool      flg;
7169   PetscErrorCode ierr;
7170 
7171   PetscFunctionBegin;
7172   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7173   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7174   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7175   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7176   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7177   tmpLabel->label  = label;
7178   tmpLabel->output = PETSC_TRUE;
7179   for (p=&dm->labels; (l=*p); p=&l->next) {}
7180   *p = tmpLabel;
7181   ierr = PetscObjectReference((PetscObject)label);CHKERRQ(ierr);
7182   ierr = PetscStrcmp(lname, "depth", &flg);CHKERRQ(ierr);
7183   if (flg) dm->depthLabel = label;
7184   PetscFunctionReturn(0);
7185 }
7186 
7187 /*@C
7188   DMRemoveLabel - Remove the label given by name from this mesh
7189 
7190   Not Collective
7191 
7192   Input Parameters:
7193 + dm   - The DM object
7194 - name - The label name
7195 
7196   Output Parameter:
7197 . label - The DMLabel, or NULL if the label is absent
7198 
7199   Level: developer
7200 
7201   Notes:
7202   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7203   DMLabelDestroy() on the label.
7204 
7205   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7206   call DMLabelDestroy(). Instead, the label is returned and the user is
7207   responsible of calling DMLabelDestroy() at some point.
7208 
7209 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7210 @*/
7211 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7212 {
7213   DMLabelLink    link, *pnext;
7214   PetscBool      hasLabel;
7215   const char    *lname;
7216   PetscErrorCode ierr;
7217 
7218   PetscFunctionBegin;
7219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7220   PetscValidCharPointer(name, 2);
7221   if (label) {
7222     PetscValidPointer(label, 3);
7223     *label = NULL;
7224   }
7225   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7226     ierr = PetscObjectGetName((PetscObject) link->label, &lname);CHKERRQ(ierr);
7227     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7228     if (hasLabel) {
7229       *pnext = link->next; /* Remove from list */
7230       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7231       if (hasLabel) dm->depthLabel = NULL;
7232       if (label) *label = link->label;
7233       else       {ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);}
7234       ierr = PetscFree(link);CHKERRQ(ierr);
7235       break;
7236     }
7237   }
7238   PetscFunctionReturn(0);
7239 }
7240 
7241 /*@
7242   DMRemoveLabelBySelf - Remove the label from this mesh
7243 
7244   Not Collective
7245 
7246   Input Parameters:
7247 + dm   - The DM object
7248 . label - (Optional) The DMLabel to be removed from the DM
7249 - failNotFound - Should it fail if the label is not found in the DM?
7250 
7251   Level: developer
7252 
7253   Notes:
7254   Only exactly the same instance is removed if found, name match is ignored.
7255   If the DM has an exclusive reference to the label, it gets destroyed and
7256   *label nullified.
7257 
7258 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7259 @*/
7260 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7261 {
7262   DMLabelLink    link, *pnext;
7263   PetscBool      hasLabel = PETSC_FALSE;
7264   PetscErrorCode ierr;
7265 
7266   PetscFunctionBegin;
7267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7268   PetscValidPointer(label, 2);
7269   if (!*label && !failNotFound) PetscFunctionReturn(0);
7270   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7271   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
7272   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7273     if (*label == link->label) {
7274       hasLabel = PETSC_TRUE;
7275       *pnext = link->next; /* Remove from list */
7276       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7277       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7278       ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);
7279       ierr = PetscFree(link);CHKERRQ(ierr);
7280       break;
7281     }
7282   }
7283   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7284   PetscFunctionReturn(0);
7285 }
7286 
7287 /*@C
7288   DMGetLabelOutput - Get the output flag for a given label
7289 
7290   Not Collective
7291 
7292   Input Parameters:
7293 + dm   - The DM object
7294 - name - The label name
7295 
7296   Output Parameter:
7297 . output - The flag for output
7298 
7299   Level: developer
7300 
7301 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7302 @*/
7303 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7304 {
7305   DMLabelLink    next = dm->labels;
7306   const char    *lname;
7307   PetscErrorCode ierr;
7308 
7309   PetscFunctionBegin;
7310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7311   PetscValidPointer(name, 2);
7312   PetscValidPointer(output, 3);
7313   while (next) {
7314     PetscBool flg;
7315 
7316     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7317     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7318     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7319     next = next->next;
7320   }
7321   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7322 }
7323 
7324 /*@C
7325   DMSetLabelOutput - Set the output flag for a given label
7326 
7327   Not Collective
7328 
7329   Input Parameters:
7330 + dm     - The DM object
7331 . name   - The label name
7332 - output - The flag for output
7333 
7334   Level: developer
7335 
7336 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7337 @*/
7338 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7339 {
7340   DMLabelLink    next = dm->labels;
7341   const char    *lname;
7342   PetscErrorCode ierr;
7343 
7344   PetscFunctionBegin;
7345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7346   PetscValidCharPointer(name, 2);
7347   while (next) {
7348     PetscBool flg;
7349 
7350     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7351     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7352     if (flg) {next->output = output; PetscFunctionReturn(0);}
7353     next = next->next;
7354   }
7355   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7356 }
7357 
7358 /*@
7359   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7360 
7361   Collective on dmA
7362 
7363   Input Parameter:
7364 + dmA - The DM object with initial labels
7365 . dmB - The DM object with copied labels
7366 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7367 - all  - Copy all labels including "depth" and "dim" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7368 
7369   Level: intermediate
7370 
7371   Note: This is typically used when interpolating or otherwise adding to a mesh
7372 
7373 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7374 @*/
7375 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7376 {
7377   DMLabel        label, labelNew;
7378   const char    *name;
7379   PetscBool      flg;
7380   DMLabelLink    link;
7381   PetscErrorCode ierr;
7382 
7383   PetscFunctionBegin;
7384   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7385   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7386   PetscValidLogicalCollectiveEnum(dmA, mode,3);
7387   PetscValidLogicalCollectiveBool(dmA, all, 4);
7388   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7389   if (dmA == dmB) PetscFunctionReturn(0);
7390   for (link=dmA->labels; link; link=link->next) {
7391     label=link->label;
7392     ierr = PetscObjectGetName((PetscObject)label, &name);CHKERRQ(ierr);
7393     if (!all) {
7394       ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7395       if (flg) continue;
7396       ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7397       if (flg) continue;
7398     } else {
7399       dmB->depthLabel = dmA->depthLabel;
7400     }
7401     if (mode==PETSC_COPY_VALUES) {
7402       ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7403     } else {
7404       labelNew = label;
7405     }
7406     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7407     if (mode==PETSC_COPY_VALUES) {ierr = DMLabelDestroy(&labelNew);CHKERRQ(ierr);}
7408   }
7409   PetscFunctionReturn(0);
7410 }
7411 
7412 /*@
7413   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7414 
7415   Input Parameter:
7416 . dm - The DM object
7417 
7418   Output Parameter:
7419 . cdm - The coarse DM
7420 
7421   Level: intermediate
7422 
7423 .seealso: DMSetCoarseDM()
7424 @*/
7425 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7426 {
7427   PetscFunctionBegin;
7428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7429   PetscValidPointer(cdm, 2);
7430   *cdm = dm->coarseMesh;
7431   PetscFunctionReturn(0);
7432 }
7433 
7434 /*@
7435   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7436 
7437   Input Parameters:
7438 + dm - The DM object
7439 - cdm - The coarse DM
7440 
7441   Level: intermediate
7442 
7443 .seealso: DMGetCoarseDM()
7444 @*/
7445 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7446 {
7447   PetscErrorCode ierr;
7448 
7449   PetscFunctionBegin;
7450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7451   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7452   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7453   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7454   dm->coarseMesh = cdm;
7455   PetscFunctionReturn(0);
7456 }
7457 
7458 /*@
7459   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7460 
7461   Input Parameter:
7462 . dm - The DM object
7463 
7464   Output Parameter:
7465 . fdm - The fine DM
7466 
7467   Level: intermediate
7468 
7469 .seealso: DMSetFineDM()
7470 @*/
7471 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7472 {
7473   PetscFunctionBegin;
7474   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7475   PetscValidPointer(fdm, 2);
7476   *fdm = dm->fineMesh;
7477   PetscFunctionReturn(0);
7478 }
7479 
7480 /*@
7481   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7482 
7483   Input Parameters:
7484 + dm - The DM object
7485 - fdm - The fine DM
7486 
7487   Level: intermediate
7488 
7489 .seealso: DMGetFineDM()
7490 @*/
7491 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7492 {
7493   PetscErrorCode ierr;
7494 
7495   PetscFunctionBegin;
7496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7497   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7498   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7499   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7500   dm->fineMesh = fdm;
7501   PetscFunctionReturn(0);
7502 }
7503 
7504 /*=== DMBoundary code ===*/
7505 
7506 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7507 {
7508   PetscInt       d;
7509   PetscErrorCode ierr;
7510 
7511   PetscFunctionBegin;
7512   for (d = 0; d < dm->Nds; ++d) {
7513     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7514   }
7515   PetscFunctionReturn(0);
7516 }
7517 
7518 /*@C
7519   DMAddBoundary - Add a boundary condition to the model
7520 
7521   Input Parameters:
7522 + dm          - The DM, with a PetscDS that matches the problem being constrained
7523 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7524 . name        - The BC name
7525 . labelname   - The label defining constrained points
7526 . field       - The field to constrain
7527 . numcomps    - The number of constrained field components (0 will constrain all fields)
7528 . comps       - An array of constrained component numbers
7529 . bcFunc      - A pointwise function giving boundary values
7530 . numids      - The number of DMLabel ids for constrained points
7531 . ids         - An array of ids for constrained points
7532 - ctx         - An optional user context for bcFunc
7533 
7534   Options Database Keys:
7535 + -bc_<boundary name> <num> - Overrides the boundary ids
7536 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7537 
7538   Level: developer
7539 
7540 .seealso: DMGetBoundary()
7541 @*/
7542 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)
7543 {
7544   PetscDS        ds;
7545   PetscErrorCode ierr;
7546 
7547   PetscFunctionBegin;
7548   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7549   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7550   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7551   PetscFunctionReturn(0);
7552 }
7553 
7554 /*@
7555   DMGetNumBoundary - Get the number of registered BC
7556 
7557   Input Parameters:
7558 . dm - The mesh object
7559 
7560   Output Parameters:
7561 . numBd - The number of BC
7562 
7563   Level: intermediate
7564 
7565 .seealso: DMAddBoundary(), DMGetBoundary()
7566 @*/
7567 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7568 {
7569   PetscDS        ds;
7570   PetscErrorCode ierr;
7571 
7572   PetscFunctionBegin;
7573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7574   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7575   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7576   PetscFunctionReturn(0);
7577 }
7578 
7579 /*@C
7580   DMGetBoundary - Get a model boundary condition
7581 
7582   Input Parameters:
7583 + dm          - The mesh object
7584 - bd          - The BC number
7585 
7586   Output Parameters:
7587 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7588 . name        - The BC name
7589 . labelname   - The label defining constrained points
7590 . field       - The field to constrain
7591 . numcomps    - The number of constrained field components
7592 . comps       - An array of constrained component numbers
7593 . bcFunc      - A pointwise function giving boundary values
7594 . numids      - The number of DMLabel ids for constrained points
7595 . ids         - An array of ids for constrained points
7596 - ctx         - An optional user context for bcFunc
7597 
7598   Options Database Keys:
7599 + -bc_<boundary name> <num> - Overrides the boundary ids
7600 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7601 
7602   Level: developer
7603 
7604 .seealso: DMAddBoundary()
7605 @*/
7606 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)
7607 {
7608   PetscDS        ds;
7609   PetscErrorCode ierr;
7610 
7611   PetscFunctionBegin;
7612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7613   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7614   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7615   PetscFunctionReturn(0);
7616 }
7617 
7618 static PetscErrorCode DMPopulateBoundary(DM dm)
7619 {
7620   PetscDS        ds;
7621   DMBoundary    *lastnext;
7622   DSBoundary     dsbound;
7623   PetscErrorCode ierr;
7624 
7625   PetscFunctionBegin;
7626   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7627   dsbound = ds->boundary;
7628   if (dm->boundary) {
7629     DMBoundary next = dm->boundary;
7630 
7631     /* quick check to see if the PetscDS has changed */
7632     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7633     /* the PetscDS has changed: tear down and rebuild */
7634     while (next) {
7635       DMBoundary b = next;
7636 
7637       next = b->next;
7638       ierr = PetscFree(b);CHKERRQ(ierr);
7639     }
7640     dm->boundary = NULL;
7641   }
7642 
7643   lastnext = &(dm->boundary);
7644   while (dsbound) {
7645     DMBoundary dmbound;
7646 
7647     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7648     dmbound->dsboundary = dsbound;
7649     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7650     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7651     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7652     *lastnext = dmbound;
7653     lastnext = &(dmbound->next);
7654     dsbound = dsbound->next;
7655   }
7656   PetscFunctionReturn(0);
7657 }
7658 
7659 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7660 {
7661   DMBoundary     b;
7662   PetscErrorCode ierr;
7663 
7664   PetscFunctionBegin;
7665   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7666   PetscValidBoolPointer(isBd, 3);
7667   *isBd = PETSC_FALSE;
7668   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7669   b = dm->boundary;
7670   while (b && !(*isBd)) {
7671     DMLabel    label = b->label;
7672     DSBoundary dsb = b->dsboundary;
7673 
7674     if (label) {
7675       PetscInt i;
7676 
7677       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7678         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7679       }
7680     }
7681     b = b->next;
7682   }
7683   PetscFunctionReturn(0);
7684 }
7685 
7686 /*@C
7687   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
7688 
7689   Collective on DM
7690 
7691   Input Parameters:
7692 + dm      - The DM
7693 . time    - The time
7694 . funcs   - The coordinate functions to evaluate, one per field
7695 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7696 - mode    - The insertion mode for values
7697 
7698   Output Parameter:
7699 . X - vector
7700 
7701    Calling sequence of func:
7702 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7703 
7704 +  dim - The spatial dimension
7705 .  x   - The coordinates
7706 .  Nf  - The number of fields
7707 .  u   - The output field values
7708 -  ctx - optional user-defined function context
7709 
7710   Level: developer
7711 
7712 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7713 @*/
7714 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7715 {
7716   Vec            localX;
7717   PetscErrorCode ierr;
7718 
7719   PetscFunctionBegin;
7720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7721   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7722   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7723   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7724   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7725   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7726   PetscFunctionReturn(0);
7727 }
7728 
7729 /*@C
7730   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
7731 
7732   Not collective
7733 
7734   Input Parameters:
7735 + dm      - The DM
7736 . time    - The time
7737 . funcs   - The coordinate functions to evaluate, one per field
7738 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7739 - mode    - The insertion mode for values
7740 
7741   Output Parameter:
7742 . localX - vector
7743 
7744    Calling sequence of func:
7745 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7746 
7747 +  dim - The spatial dimension
7748 .  x   - The coordinates
7749 .  Nf  - The number of fields
7750 .  u   - The output field values
7751 -  ctx - optional user-defined function context
7752 
7753   Level: developer
7754 
7755 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7756 @*/
7757 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7758 {
7759   PetscErrorCode ierr;
7760 
7761   PetscFunctionBegin;
7762   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7763   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7764   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7765   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7766   PetscFunctionReturn(0);
7767 }
7768 
7769 /*@C
7770   DMProjectFunctionLabel - This projects the given function into the function space provided, putting the coefficients in a global vector, setting values only for points in the given label.
7771 
7772   Collective on DM
7773 
7774   Input Parameters:
7775 + dm      - The DM
7776 . time    - The time
7777 . label   - The DMLabel selecting the portion of the mesh for projection
7778 . funcs   - The coordinate functions to evaluate, one per field
7779 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7780 - mode    - The insertion mode for values
7781 
7782   Output Parameter:
7783 . X - vector
7784 
7785    Calling sequence of func:
7786 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7787 
7788 +  dim - The spatial dimension
7789 .  x   - The coordinates
7790 .  Nf  - The number of fields
7791 .  u   - The output field values
7792 -  ctx - optional user-defined function context
7793 
7794   Level: developer
7795 
7796 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
7797 @*/
7798 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)
7799 {
7800   Vec            localX;
7801   PetscErrorCode ierr;
7802 
7803   PetscFunctionBegin;
7804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7805   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7806   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7807   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7808   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7809   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7810   PetscFunctionReturn(0);
7811 }
7812 
7813 /*@C
7814   DMProjectFunctionLabelLocal - This projects the given function into the function space provided, putting the coefficients in a local vector, setting values only for points in the given label.
7815 
7816   Not collective
7817 
7818   Input Parameters:
7819 + dm      - The DM
7820 . time    - The time
7821 . label   - The DMLabel selecting the portion of the mesh for projection
7822 . funcs   - The coordinate functions to evaluate, one per field
7823 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7824 - mode    - The insertion mode for values
7825 
7826   Output Parameter:
7827 . localX - vector
7828 
7829    Calling sequence of func:
7830 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7831 
7832 +  dim - The spatial dimension
7833 .  x   - The coordinates
7834 .  Nf  - The number of fields
7835 .  u   - The output field values
7836 -  ctx - optional user-defined function context
7837 
7838   Level: developer
7839 
7840 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7841 @*/
7842 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)
7843 {
7844   PetscErrorCode ierr;
7845 
7846   PetscFunctionBegin;
7847   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7848   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7849   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7850   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7851   PetscFunctionReturn(0);
7852 }
7853 
7854 /*@C
7855   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
7856 
7857   Not collective
7858 
7859   Input Parameters:
7860 + dm      - The DM
7861 . time    - The time
7862 . localU  - The input field vector
7863 . funcs   - The functions to evaluate, one per field
7864 - mode    - The insertion mode for values
7865 
7866   Output Parameter:
7867 . localX  - The output vector
7868 
7869    Calling sequence of func:
7870 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7871 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7872 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7873 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7874 
7875 +  dim          - The spatial dimension
7876 .  Nf           - The number of input fields
7877 .  NfAux        - The number of input auxiliary fields
7878 .  uOff         - The offset of each field in u[]
7879 .  uOff_x       - The offset of each field in u_x[]
7880 .  u            - The field values at this point in space
7881 .  u_t          - The field time derivative at this point in space (or NULL)
7882 .  u_x          - The field derivatives at this point in space
7883 .  aOff         - The offset of each auxiliary field in u[]
7884 .  aOff_x       - The offset of each auxiliary field in u_x[]
7885 .  a            - The auxiliary field values at this point in space
7886 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7887 .  a_x          - The auxiliary field derivatives at this point in space
7888 .  t            - The current time
7889 .  x            - The coordinates of this point
7890 .  numConstants - The number of constants
7891 .  constants    - The value of each constant
7892 -  f            - The value of the function at this point in space
7893 
7894   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
7895   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
7896   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
7897   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
7898 
7899   Level: intermediate
7900 
7901 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7902 @*/
7903 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7904                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7905                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7906                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7907                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7908                                    InsertMode mode, Vec localX)
7909 {
7910   PetscErrorCode ierr;
7911 
7912   PetscFunctionBegin;
7913   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7914   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
7915   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
7916   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7917   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
7918   PetscFunctionReturn(0);
7919 }
7920 
7921 /*@C
7922   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.
7923 
7924   Not collective
7925 
7926   Input Parameters:
7927 + dm      - The DM
7928 . time    - The time
7929 . label   - The DMLabel marking the portion of the domain to output
7930 . numIds  - The number of label ids to use
7931 . ids     - The label ids to use for marking
7932 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
7933 . comps   - The components to set in the output, or NULL for all components
7934 . localU  - The input field vector
7935 . funcs   - The functions to evaluate, one per field
7936 - mode    - The insertion mode for values
7937 
7938   Output Parameter:
7939 . localX  - The output vector
7940 
7941    Calling sequence of func:
7942 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7943 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7944 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7945 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7946 
7947 +  dim          - The spatial dimension
7948 .  Nf           - The number of input fields
7949 .  NfAux        - The number of input auxiliary fields
7950 .  uOff         - The offset of each field in u[]
7951 .  uOff_x       - The offset of each field in u_x[]
7952 .  u            - The field values at this point in space
7953 .  u_t          - The field time derivative at this point in space (or NULL)
7954 .  u_x          - The field derivatives at this point in space
7955 .  aOff         - The offset of each auxiliary field in u[]
7956 .  aOff_x       - The offset of each auxiliary field in u_x[]
7957 .  a            - The auxiliary field values at this point in space
7958 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7959 .  a_x          - The auxiliary field derivatives at this point in space
7960 .  t            - The current time
7961 .  x            - The coordinates of this point
7962 .  numConstants - The number of constants
7963 .  constants    - The value of each constant
7964 -  f            - The value of the function at this point in space
7965 
7966   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
7967   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
7968   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
7969   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
7970 
7971   Level: intermediate
7972 
7973 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7974 @*/
7975 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7976                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7977                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7978                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7979                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7980                                         InsertMode mode, Vec localX)
7981 {
7982   PetscErrorCode ierr;
7983 
7984   PetscFunctionBegin;
7985   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7986   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
7987   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
7988   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7989   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
7990   PetscFunctionReturn(0);
7991 }
7992 
7993 /*@C
7994   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
7995 
7996   Input Parameters:
7997 + dm    - The DM
7998 . time  - The time
7999 . funcs - The functions to evaluate for each field component
8000 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8001 - X     - The coefficient vector u_h, a global vector
8002 
8003   Output Parameter:
8004 . diff - The diff ||u - u_h||_2
8005 
8006   Level: developer
8007 
8008 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8009 @*/
8010 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8011 {
8012   PetscErrorCode ierr;
8013 
8014   PetscFunctionBegin;
8015   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8016   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8017   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8018   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8019   PetscFunctionReturn(0);
8020 }
8021 
8022 /*@C
8023   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8024 
8025   Collective on dm
8026 
8027   Input Parameters:
8028 + dm    - The DM
8029 , time  - The time
8030 . funcs - The gradient functions to evaluate for each field component
8031 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8032 . X     - The coefficient vector u_h, a global vector
8033 - n     - The vector to project along
8034 
8035   Output Parameter:
8036 . diff - The diff ||(grad u - grad u_h) . n||_2
8037 
8038   Level: developer
8039 
8040 .seealso: DMProjectFunction(), DMComputeL2Diff()
8041 @*/
8042 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)
8043 {
8044   PetscErrorCode ierr;
8045 
8046   PetscFunctionBegin;
8047   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8048   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8049   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8050   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
8051   PetscFunctionReturn(0);
8052 }
8053 
8054 /*@C
8055   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8056 
8057   Collective on dm
8058 
8059   Input Parameters:
8060 + dm    - The DM
8061 . time  - The time
8062 . funcs - The functions to evaluate for each field component
8063 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8064 - X     - The coefficient vector u_h, a global vector
8065 
8066   Output Parameter:
8067 . diff - The array of differences, ||u^f - u^f_h||_2
8068 
8069   Level: developer
8070 
8071 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8072 @*/
8073 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8074 {
8075   PetscErrorCode ierr;
8076 
8077   PetscFunctionBegin;
8078   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8079   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8080   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8081   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8082   PetscFunctionReturn(0);
8083 }
8084 
8085 /*@C
8086   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8087                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8088 
8089   Collective on dm
8090 
8091   Input parameters:
8092 + dm - the pre-adaptation DM object
8093 - label - label with the flags
8094 
8095   Output parameters:
8096 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8097 
8098   Level: intermediate
8099 
8100 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8101 @*/
8102 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8103 {
8104   PetscErrorCode ierr;
8105 
8106   PetscFunctionBegin;
8107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8108   PetscValidPointer(label,2);
8109   PetscValidPointer(dmAdapt,3);
8110   *dmAdapt = NULL;
8111   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8112   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
8113   PetscFunctionReturn(0);
8114 }
8115 
8116 /*@C
8117   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8118 
8119   Input Parameters:
8120 + dm - The DM object
8121 . metric - The metric to which the mesh is adapted, defined vertex-wise.
8122 - 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_".
8123 
8124   Output Parameter:
8125 . dmAdapt  - Pointer to the DM object containing the adapted mesh
8126 
8127   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8128 
8129   Level: advanced
8130 
8131 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8132 @*/
8133 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8134 {
8135   PetscErrorCode ierr;
8136 
8137   PetscFunctionBegin;
8138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8139   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
8140   if (bdLabel) PetscValidPointer(bdLabel, 3);
8141   PetscValidPointer(dmAdapt, 4);
8142   *dmAdapt = NULL;
8143   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8144   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
8145   PetscFunctionReturn(0);
8146 }
8147 
8148 /*@C
8149  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8150 
8151  Not Collective
8152 
8153  Input Parameter:
8154  . dm    - The DM
8155 
8156  Output Parameter:
8157  . nranks - the number of neighbours
8158  . ranks - the neighbors ranks
8159 
8160  Notes:
8161  Do not free the array, it is freed when the DM is destroyed.
8162 
8163  Level: beginner
8164 
8165  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8166 @*/
8167 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8168 {
8169   PetscErrorCode ierr;
8170 
8171   PetscFunctionBegin;
8172   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8173   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8174   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
8175   PetscFunctionReturn(0);
8176 }
8177 
8178 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8179 
8180 /*
8181     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8182     This has be a different function because it requires DM which is not defined in the Mat library
8183 */
8184 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8185 {
8186   PetscErrorCode ierr;
8187 
8188   PetscFunctionBegin;
8189   if (coloring->ctype == IS_COLORING_LOCAL) {
8190     Vec x1local;
8191     DM  dm;
8192     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8193     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8194     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
8195     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8196     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8197     x1   = x1local;
8198   }
8199   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
8200   if (coloring->ctype == IS_COLORING_LOCAL) {
8201     DM  dm;
8202     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8203     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
8204   }
8205   PetscFunctionReturn(0);
8206 }
8207 
8208 /*@
8209     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
8210 
8211     Input Parameter:
8212 .    coloring - the MatFDColoring object
8213 
8214     Developer Notes:
8215     this routine exists because the PETSc Mat library does not know about the DM objects
8216 
8217     Level: advanced
8218 
8219 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8220 @*/
8221 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8222 {
8223   PetscFunctionBegin;
8224   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8225   PetscFunctionReturn(0);
8226 }
8227 
8228 /*@
8229     DMGetCompatibility - determine if two DMs are compatible
8230 
8231     Collective
8232 
8233     Input Parameters:
8234 +    dm - the first DM
8235 -    dm2 - the second DM
8236 
8237     Output Parameters:
8238 +    compatible - whether or not the two DMs are compatible
8239 -    set - whether or not the compatible value was set
8240 
8241     Notes:
8242     Two DMs are deemed compatible if they represent the same parallel decomposition
8243     of the same topology. This implies that the section (field data) on one
8244     "makes sense" with respect to the topology and parallel decomposition of the other.
8245     Loosely speaking, compatible DMs represent the same domain and parallel
8246     decomposition, but hold different data.
8247 
8248     Typically, one would confirm compatibility if intending to simultaneously iterate
8249     over a pair of vectors obtained from different DMs.
8250 
8251     For example, two DMDA objects are compatible if they have the same local
8252     and global sizes and the same stencil width. They can have different numbers
8253     of degrees of freedom per node. Thus, one could use the node numbering from
8254     either DM in bounds for a loop over vectors derived from either DM.
8255 
8256     Consider the operation of summing data living on a 2-dof DMDA to data living
8257     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8258 .vb
8259   ...
8260   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
8261   if (set && compatible)  {
8262     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8263     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8264     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
8265     for (j=y; j<y+n; ++j) {
8266       for (i=x; i<x+m, ++i) {
8267         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8268       }
8269     }
8270     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8271     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8272   } else {
8273     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8274   }
8275   ...
8276 .ve
8277 
8278     Checking compatibility might be expensive for a given implementation of DM,
8279     or might be impossible to unambiguously confirm or deny. For this reason,
8280     this function may decline to determine compatibility, and hence users should
8281     always check the "set" output parameter.
8282 
8283     A DM is always compatible with itself.
8284 
8285     In the current implementation, DMs which live on "unequal" communicators
8286     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8287     incompatible.
8288 
8289     This function is labeled "Collective," as information about all subdomains
8290     is required on each rank. However, in DM implementations which store all this
8291     information locally, this function may be merely "Logically Collective".
8292 
8293     Developer Notes:
8294     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8295     iff B is compatible with A. Thus, this function checks the implementations
8296     of both dm and dm2 (if they are of different types), attempting to determine
8297     compatibility. It is left to DM implementers to ensure that symmetry is
8298     preserved. The simplest way to do this is, when implementing type-specific
8299     logic for this function, is to check for existing logic in the implementation
8300     of other DM types and let *set = PETSC_FALSE if found.
8301 
8302     Level: advanced
8303 
8304 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8305 @*/
8306 
8307 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
8308 {
8309   PetscErrorCode ierr;
8310   PetscMPIInt    compareResult;
8311   DMType         type,type2;
8312   PetscBool      sameType;
8313 
8314   PetscFunctionBegin;
8315   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8316   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
8317 
8318   /* Declare a DM compatible with itself */
8319   if (dm == dm2) {
8320     *set = PETSC_TRUE;
8321     *compatible = PETSC_TRUE;
8322     PetscFunctionReturn(0);
8323   }
8324 
8325   /* Declare a DM incompatible with a DM that lives on an "unequal"
8326      communicator. Note that this does not preclude compatibility with
8327      DMs living on "congruent" or "similar" communicators, but this must be
8328      determined by the implementation-specific logic */
8329   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
8330   if (compareResult == MPI_UNEQUAL) {
8331     *set = PETSC_TRUE;
8332     *compatible = PETSC_FALSE;
8333     PetscFunctionReturn(0);
8334   }
8335 
8336   /* Pass to the implementation-specific routine, if one exists. */
8337   if (dm->ops->getcompatibility) {
8338     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
8339     if (*set) PetscFunctionReturn(0);
8340   }
8341 
8342   /* If dm and dm2 are of different types, then attempt to check compatibility
8343      with an implementation of this function from dm2 */
8344   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
8345   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
8346   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
8347   if (!sameType && dm2->ops->getcompatibility) {
8348     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
8349   } else {
8350     *set = PETSC_FALSE;
8351   }
8352   PetscFunctionReturn(0);
8353 }
8354 
8355 /*@C
8356   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
8357 
8358   Logically Collective on DM
8359 
8360   Input Parameters:
8361 + DM - the DM
8362 . f - the monitor function
8363 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8364 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8365 
8366   Options Database Keys:
8367 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8368                             does not cancel those set via the options database.
8369 
8370   Notes:
8371   Several different monitoring routines may be set by calling
8372   DMMonitorSet() multiple times; all will be called in the
8373   order in which they were set.
8374 
8375   Fortran Notes:
8376   Only a single monitor function can be set for each DM object
8377 
8378   Level: intermediate
8379 
8380 .seealso: DMMonitorCancel()
8381 @*/
8382 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8383 {
8384   PetscInt       m;
8385   PetscErrorCode ierr;
8386 
8387   PetscFunctionBegin;
8388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8389   for (m = 0; m < dm->numbermonitors; ++m) {
8390     PetscBool identical;
8391 
8392     ierr = PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);CHKERRQ(ierr);
8393     if (identical) PetscFunctionReturn(0);
8394   }
8395   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8396   dm->monitor[dm->numbermonitors]          = f;
8397   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8398   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8399   PetscFunctionReturn(0);
8400 }
8401 
8402 /*@
8403   DMMonitorCancel - Clears all the monitor functions for a DM object.
8404 
8405   Logically Collective on DM
8406 
8407   Input Parameter:
8408 . dm - the DM
8409 
8410   Options Database Key:
8411 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8412   into a code by calls to DMonitorSet(), but does not cancel those
8413   set via the options database
8414 
8415   Notes:
8416   There is no way to clear one specific monitor from a DM object.
8417 
8418   Level: intermediate
8419 
8420 .seealso: DMMonitorSet()
8421 @*/
8422 PetscErrorCode DMMonitorCancel(DM dm)
8423 {
8424   PetscErrorCode ierr;
8425   PetscInt       m;
8426 
8427   PetscFunctionBegin;
8428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8429   for (m = 0; m < dm->numbermonitors; ++m) {
8430     if (dm->monitordestroy[m]) {ierr = (*dm->monitordestroy[m])(&dm->monitorcontext[m]);CHKERRQ(ierr);}
8431   }
8432   dm->numbermonitors = 0;
8433   PetscFunctionReturn(0);
8434 }
8435 
8436 /*@C
8437   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8438 
8439   Collective on DM
8440 
8441   Input Parameters:
8442 + dm   - DM object you wish to monitor
8443 . name - the monitor type one is seeking
8444 . help - message indicating what monitoring is done
8445 . manual - manual page for the monitor
8446 . monitor - the monitor function
8447 - 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
8448 
8449   Output Parameter:
8450 . flg - Flag set if the monitor was created
8451 
8452   Level: developer
8453 
8454 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8455           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8456           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8457           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8458           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8459           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8460           PetscOptionsFList(), PetscOptionsEList()
8461 @*/
8462 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8463 {
8464   PetscViewer       viewer;
8465   PetscViewerFormat format;
8466   PetscErrorCode    ierr;
8467 
8468   PetscFunctionBegin;
8469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8470   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);CHKERRQ(ierr);
8471   if (*flg) {
8472     PetscViewerAndFormat *vf;
8473 
8474     ierr = PetscViewerAndFormatCreate(viewer, format, &vf);CHKERRQ(ierr);
8475     ierr = PetscObjectDereference((PetscObject) viewer);CHKERRQ(ierr);
8476     if (monitorsetup) {ierr = (*monitorsetup)(dm, vf);CHKERRQ(ierr);}
8477     ierr = DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);CHKERRQ(ierr);
8478   }
8479   PetscFunctionReturn(0);
8480 }
8481 
8482 /*@
8483    DMMonitor - runs the user provided monitor routines, if they exist
8484 
8485    Collective on DM
8486 
8487    Input Parameters:
8488 .  dm - The DM
8489 
8490    Level: developer
8491 
8492 .seealso: DMMonitorSet()
8493 @*/
8494 PetscErrorCode DMMonitor(DM dm)
8495 {
8496   PetscInt       m;
8497   PetscErrorCode ierr;
8498 
8499   PetscFunctionBegin;
8500   if (!dm) PetscFunctionReturn(0);
8501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8502   for (m = 0; m < dm->numbermonitors; ++m) {
8503     ierr = (*dm->monitor[m])(dm, dm->monitorcontext[m]);CHKERRQ(ierr);
8504   }
8505   PetscFunctionReturn(0);
8506 }
8507