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