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