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