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