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