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