xref: /petsc/src/dm/interface/dm.c (revision 9a64c4a8377f7cc3304b0a5261e5e80322751d15)
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     DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
2828 
2829     Not Collective
2830 
2831     Input Parameters:
2832 +   dm - the DM object
2833 -   level - number of coarsenings
2834 
2835     Level: developer
2836 
2837 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2838 @*/
2839 PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
2840 {
2841   PetscFunctionBegin;
2842   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2843   dm->leveldown = level;
2844   PetscFunctionReturn(0);
2845 }
2846 
2847 
2848 
2849 /*@C
2850     DMRefineHierarchy - Refines a DM object, all levels at once
2851 
2852     Collective on DM
2853 
2854     Input Parameter:
2855 +   dm - the DM object
2856 -   nlevels - the number of levels of refinement
2857 
2858     Output Parameter:
2859 .   dmf - the refined DM hierarchy
2860 
2861     Level: developer
2862 
2863 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2864 
2865 @*/
2866 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2867 {
2868   PetscErrorCode ierr;
2869 
2870   PetscFunctionBegin;
2871   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2872   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2873   if (nlevels == 0) PetscFunctionReturn(0);
2874   if (dm->ops->refinehierarchy) {
2875     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2876   } else if (dm->ops->refine) {
2877     PetscInt i;
2878 
2879     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2880     for (i=1; i<nlevels; i++) {
2881       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2882     }
2883   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2884   PetscFunctionReturn(0);
2885 }
2886 
2887 /*@C
2888     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2889 
2890     Collective on DM
2891 
2892     Input Parameter:
2893 +   dm - the DM object
2894 -   nlevels - the number of levels of coarsening
2895 
2896     Output Parameter:
2897 .   dmc - the coarsened DM hierarchy
2898 
2899     Level: developer
2900 
2901 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2902 
2903 @*/
2904 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2905 {
2906   PetscErrorCode ierr;
2907 
2908   PetscFunctionBegin;
2909   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2910   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2911   if (nlevels == 0) PetscFunctionReturn(0);
2912   PetscValidPointer(dmc,3);
2913   if (dm->ops->coarsenhierarchy) {
2914     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2915   } else if (dm->ops->coarsen) {
2916     PetscInt i;
2917 
2918     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2919     for (i=1; i<nlevels; i++) {
2920       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2921     }
2922   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2923   PetscFunctionReturn(0);
2924 }
2925 
2926 /*@
2927    DMCreateAggregates - Gets the aggregates that map between
2928    grids associated with two DMs.
2929 
2930    Collective on DM
2931 
2932    Input Parameters:
2933 +  dmc - the coarse grid DM
2934 -  dmf - the fine grid DM
2935 
2936    Output Parameters:
2937 .  rest - the restriction matrix (transpose of the projection matrix)
2938 
2939    Level: intermediate
2940 
2941 .keywords: interpolation, restriction, multigrid
2942 
2943 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2944 @*/
2945 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2946 {
2947   PetscErrorCode ierr;
2948 
2949   PetscFunctionBegin;
2950   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2951   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2952   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2953   PetscFunctionReturn(0);
2954 }
2955 
2956 /*@C
2957     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2958 
2959     Not Collective
2960 
2961     Input Parameters:
2962 +   dm - the DM object
2963 -   destroy - the destroy function
2964 
2965     Level: intermediate
2966 
2967 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2968 
2969 @*/
2970 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2971 {
2972   PetscFunctionBegin;
2973   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2974   dm->ctxdestroy = destroy;
2975   PetscFunctionReturn(0);
2976 }
2977 
2978 /*@
2979     DMSetApplicationContext - Set a user context into a DM object
2980 
2981     Not Collective
2982 
2983     Input Parameters:
2984 +   dm - the DM object
2985 -   ctx - the user context
2986 
2987     Level: intermediate
2988 
2989 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2990 
2991 @*/
2992 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2993 {
2994   PetscFunctionBegin;
2995   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2996   dm->ctx = ctx;
2997   PetscFunctionReturn(0);
2998 }
2999 
3000 /*@
3001     DMGetApplicationContext - Gets a user context from a DM object
3002 
3003     Not Collective
3004 
3005     Input Parameter:
3006 .   dm - the DM object
3007 
3008     Output Parameter:
3009 .   ctx - the user context
3010 
3011     Level: intermediate
3012 
3013 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3014 
3015 @*/
3016 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3017 {
3018   PetscFunctionBegin;
3019   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3020   *(void**)ctx = dm->ctx;
3021   PetscFunctionReturn(0);
3022 }
3023 
3024 /*@C
3025     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3026 
3027     Logically Collective on DM
3028 
3029     Input Parameter:
3030 +   dm - the DM object
3031 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3032 
3033     Level: intermediate
3034 
3035 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3036          DMSetJacobian()
3037 
3038 @*/
3039 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3040 {
3041   PetscFunctionBegin;
3042   dm->ops->computevariablebounds = f;
3043   PetscFunctionReturn(0);
3044 }
3045 
3046 /*@
3047     DMHasVariableBounds - does the DM object have a variable bounds function?
3048 
3049     Not Collective
3050 
3051     Input Parameter:
3052 .   dm - the DM object to destroy
3053 
3054     Output Parameter:
3055 .   flg - PETSC_TRUE if the variable bounds function exists
3056 
3057     Level: developer
3058 
3059 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3060 
3061 @*/
3062 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
3063 {
3064   PetscFunctionBegin;
3065   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3066   PetscFunctionReturn(0);
3067 }
3068 
3069 /*@C
3070     DMComputeVariableBounds - compute variable bounds used by SNESVI.
3071 
3072     Logically Collective on DM
3073 
3074     Input Parameters:
3075 .   dm - the DM object
3076 
3077     Output parameters:
3078 +   xl - lower bound
3079 -   xu - upper bound
3080 
3081     Level: advanced
3082 
3083     Notes:
3084     This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3085 
3086 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3087 
3088 @*/
3089 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3090 {
3091   PetscErrorCode ierr;
3092 
3093   PetscFunctionBegin;
3094   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
3095   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
3096   if (dm->ops->computevariablebounds) {
3097     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
3098   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
3099   PetscFunctionReturn(0);
3100 }
3101 
3102 /*@
3103     DMHasColoring - does the DM object have a method of providing a coloring?
3104 
3105     Not Collective
3106 
3107     Input Parameter:
3108 .   dm - the DM object
3109 
3110     Output Parameter:
3111 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3112 
3113     Level: developer
3114 
3115 .seealso DMHasFunction(), DMCreateColoring()
3116 
3117 @*/
3118 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
3119 {
3120   PetscFunctionBegin;
3121   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3122   PetscFunctionReturn(0);
3123 }
3124 
3125 /*@
3126     DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3127 
3128     Not Collective
3129 
3130     Input Parameter:
3131 .   dm - the DM object
3132 
3133     Output Parameter:
3134 .   flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3135 
3136     Level: developer
3137 
3138 .seealso DMHasFunction(), DMCreateRestriction()
3139 
3140 @*/
3141 PetscErrorCode  DMHasCreateRestriction(DM dm,PetscBool  *flg)
3142 {
3143   PetscFunctionBegin;
3144   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3145   PetscFunctionReturn(0);
3146 }
3147 
3148 
3149 /*@
3150     DMHasCreateInjection - does the DM object have a method of providing an injection?
3151 
3152     Not Collective
3153 
3154     Input Parameter:
3155 .   dm - the DM object
3156 
3157     Output Parameter:
3158 .   flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3159 
3160     Level: developer
3161 
3162 .seealso DMHasFunction(), DMCreateInjection()
3163 
3164 @*/
3165 PetscErrorCode  DMHasCreateInjection(DM dm,PetscBool  *flg)
3166 {
3167   PetscErrorCode ierr;
3168   PetscFunctionBegin;
3169   if (!dm->ops->hascreateinjection) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DMHasCreateInjection not implemented for this type");
3170   ierr = (*dm->ops->hascreateinjection)(dm,flg);CHKERRQ(ierr);
3171   PetscFunctionReturn(0);
3172 }
3173 
3174 /*@C
3175     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
3176 
3177     Collective on DM
3178 
3179     Input Parameter:
3180 +   dm - the DM object
3181 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
3182 
3183     Level: developer
3184 
3185 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3186 
3187 @*/
3188 PetscErrorCode  DMSetVec(DM dm,Vec x)
3189 {
3190   PetscErrorCode ierr;
3191 
3192   PetscFunctionBegin;
3193   if (x) {
3194     if (!dm->x) {
3195       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
3196     }
3197     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
3198   } else if (dm->x) {
3199     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
3200   }
3201   PetscFunctionReturn(0);
3202 }
3203 
3204 PetscFunctionList DMList              = NULL;
3205 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3206 
3207 /*@C
3208   DMSetType - Builds a DM, for a particular DM implementation.
3209 
3210   Collective on DM
3211 
3212   Input Parameters:
3213 + dm     - The DM object
3214 - method - The name of the DM type
3215 
3216   Options Database Key:
3217 . -dm_type <type> - Sets the DM type; use -help for a list of available types
3218 
3219   Notes:
3220   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3221 
3222   Level: intermediate
3223 
3224 .keywords: DM, set, type
3225 .seealso: DMGetType(), DMCreate()
3226 @*/
3227 PetscErrorCode  DMSetType(DM dm, DMType method)
3228 {
3229   PetscErrorCode (*r)(DM);
3230   PetscBool      match;
3231   PetscErrorCode ierr;
3232 
3233   PetscFunctionBegin;
3234   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
3235   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
3236   if (match) PetscFunctionReturn(0);
3237 
3238   ierr = DMRegisterAll();CHKERRQ(ierr);
3239   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
3240   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3241 
3242   if (dm->ops->destroy) {
3243     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
3244     dm->ops->destroy = NULL;
3245   }
3246   ierr = (*r)(dm);CHKERRQ(ierr);
3247   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
3248   PetscFunctionReturn(0);
3249 }
3250 
3251 /*@C
3252   DMGetType - Gets the DM type name (as a string) from the DM.
3253 
3254   Not Collective
3255 
3256   Input Parameter:
3257 . dm  - The DM
3258 
3259   Output Parameter:
3260 . type - The DM type name
3261 
3262   Level: intermediate
3263 
3264 .keywords: DM, get, type, name
3265 .seealso: DMSetType(), DMCreate()
3266 @*/
3267 PetscErrorCode  DMGetType(DM dm, DMType *type)
3268 {
3269   PetscErrorCode ierr;
3270 
3271   PetscFunctionBegin;
3272   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
3273   PetscValidPointer(type,2);
3274   ierr = DMRegisterAll();CHKERRQ(ierr);
3275   *type = ((PetscObject)dm)->type_name;
3276   PetscFunctionReturn(0);
3277 }
3278 
3279 /*@C
3280   DMConvert - Converts a DM to another DM, either of the same or different type.
3281 
3282   Collective on DM
3283 
3284   Input Parameters:
3285 + dm - the DM
3286 - newtype - new DM type (use "same" for the same type)
3287 
3288   Output Parameter:
3289 . M - pointer to new DM
3290 
3291   Notes:
3292   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3293   the MPI communicator of the generated DM is always the same as the communicator
3294   of the input DM.
3295 
3296   Level: intermediate
3297 
3298 .seealso: DMCreate()
3299 @*/
3300 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3301 {
3302   DM             B;
3303   char           convname[256];
3304   PetscBool      sametype/*, issame */;
3305   PetscErrorCode ierr;
3306 
3307   PetscFunctionBegin;
3308   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3309   PetscValidType(dm,1);
3310   PetscValidPointer(M,3);
3311   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
3312   /* ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr); */
3313   if (sametype) {
3314     *M   = dm;
3315     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
3316     PetscFunctionReturn(0);
3317   } else {
3318     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3319 
3320     /*
3321        Order of precedence:
3322        1) See if a specialized converter is known to the current DM.
3323        2) See if a specialized converter is known to the desired DM class.
3324        3) See if a good general converter is registered for the desired class
3325        4) See if a good general converter is known for the current matrix.
3326        5) Use a really basic converter.
3327     */
3328 
3329     /* 1) See if a specialized converter is known to the current DM and the desired class */
3330     ierr = PetscStrncpy(convname,"DMConvert_",sizeof(convname));CHKERRQ(ierr);
3331     ierr = PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));CHKERRQ(ierr);
3332     ierr = PetscStrlcat(convname,"_",sizeof(convname));CHKERRQ(ierr);
3333     ierr = PetscStrlcat(convname,newtype,sizeof(convname));CHKERRQ(ierr);
3334     ierr = PetscStrlcat(convname,"_C",sizeof(convname));CHKERRQ(ierr);
3335     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
3336     if (conv) goto foundconv;
3337 
3338     /* 2)  See if a specialized converter is known to the desired DM class. */
3339     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
3340     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
3341     ierr = PetscStrncpy(convname,"DMConvert_",sizeof(convname));CHKERRQ(ierr);
3342     ierr = PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));CHKERRQ(ierr);
3343     ierr = PetscStrlcat(convname,"_",sizeof(convname));CHKERRQ(ierr);
3344     ierr = PetscStrlcat(convname,newtype,sizeof(convname));CHKERRQ(ierr);
3345     ierr = PetscStrlcat(convname,"_C",sizeof(convname));CHKERRQ(ierr);
3346     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
3347     if (conv) {
3348       ierr = DMDestroy(&B);CHKERRQ(ierr);
3349       goto foundconv;
3350     }
3351 
3352 #if 0
3353     /* 3) See if a good general converter is registered for the desired class */
3354     conv = B->ops->convertfrom;
3355     ierr = DMDestroy(&B);CHKERRQ(ierr);
3356     if (conv) goto foundconv;
3357 
3358     /* 4) See if a good general converter is known for the current matrix */
3359     if (dm->ops->convert) {
3360       conv = dm->ops->convert;
3361     }
3362     if (conv) goto foundconv;
3363 #endif
3364 
3365     /* 5) Use a really basic converter. */
3366     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3367 
3368 foundconv:
3369     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
3370     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
3371     /* Things that are independent of DM type: We should consult DMClone() here */
3372     {
3373       PetscBool             isper;
3374       const PetscReal      *maxCell, *L;
3375       const DMBoundaryType *bd;
3376       ierr = DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);CHKERRQ(ierr);
3377       ierr = DMSetPeriodicity(*M, isper, maxCell,  L,  bd);CHKERRQ(ierr);
3378     }
3379     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
3380   }
3381   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
3382   PetscFunctionReturn(0);
3383 }
3384 
3385 /*--------------------------------------------------------------------------------------------------------------------*/
3386 
3387 /*@C
3388   DMRegister -  Adds a new DM component implementation
3389 
3390   Not Collective
3391 
3392   Input Parameters:
3393 + name        - The name of a new user-defined creation routine
3394 - create_func - The creation routine itself
3395 
3396   Notes:
3397   DMRegister() may be called multiple times to add several user-defined DMs
3398 
3399 
3400   Sample usage:
3401 .vb
3402     DMRegister("my_da", MyDMCreate);
3403 .ve
3404 
3405   Then, your DM type can be chosen with the procedural interface via
3406 .vb
3407     DMCreate(MPI_Comm, DM *);
3408     DMSetType(DM,"my_da");
3409 .ve
3410    or at runtime via the option
3411 .vb
3412     -da_type my_da
3413 .ve
3414 
3415   Level: advanced
3416 
3417 .keywords: DM, register
3418 .seealso: DMRegisterAll(), DMRegisterDestroy()
3419 
3420 @*/
3421 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3422 {
3423   PetscErrorCode ierr;
3424 
3425   PetscFunctionBegin;
3426   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
3427   PetscFunctionReturn(0);
3428 }
3429 
3430 /*@C
3431   DMLoad - Loads a DM that has been stored in binary  with DMView().
3432 
3433   Collective on PetscViewer
3434 
3435   Input Parameters:
3436 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3437            some related function before a call to DMLoad().
3438 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3439            HDF5 file viewer, obtained from PetscViewerHDF5Open()
3440 
3441    Level: intermediate
3442 
3443   Notes:
3444    The type is determined by the data in the file, any type set into the DM before this call is ignored.
3445 
3446   Notes for advanced users:
3447   Most users should not need to know the details of the binary storage
3448   format, since DMLoad() and DMView() completely hide these details.
3449   But for anyone who's interested, the standard binary matrix storage
3450   format is
3451 .vb
3452      has not yet been determined
3453 .ve
3454 
3455 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3456 @*/
3457 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3458 {
3459   PetscBool      isbinary, ishdf5;
3460   PetscErrorCode ierr;
3461 
3462   PetscFunctionBegin;
3463   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
3464   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3465   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
3466   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
3467   if (isbinary) {
3468     PetscInt classid;
3469     char     type[256];
3470 
3471     ierr = PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);CHKERRQ(ierr);
3472     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3473     ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
3474     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
3475     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3476   } else if (ishdf5) {
3477     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3478   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3479   PetscFunctionReturn(0);
3480 }
3481 
3482 /******************************** FEM Support **********************************/
3483 
3484 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3485 {
3486   PetscInt       f;
3487   PetscErrorCode ierr;
3488 
3489   PetscFunctionBegin;
3490   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3491   for (f = 0; f < len; ++f) {
3492     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3493   }
3494   PetscFunctionReturn(0);
3495 }
3496 
3497 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3498 {
3499   PetscInt       f, g;
3500   PetscErrorCode ierr;
3501 
3502   PetscFunctionBegin;
3503   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3504   for (f = 0; f < rows; ++f) {
3505     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3506     for (g = 0; g < cols; ++g) {
3507       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3508     }
3509     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3510   }
3511   PetscFunctionReturn(0);
3512 }
3513 
3514 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3515 {
3516   PetscInt          localSize, bs;
3517   PetscMPIInt       size;
3518   Vec               x, xglob;
3519   const PetscScalar *xarray;
3520   PetscErrorCode    ierr;
3521 
3522   PetscFunctionBegin;
3523   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);CHKERRQ(ierr);
3524   ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3525   ierr = VecCopy(X, x);CHKERRQ(ierr);
3526   ierr = VecChop(x, tol);CHKERRQ(ierr);
3527   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);CHKERRQ(ierr);
3528   if (size > 1) {
3529     ierr = VecGetLocalSize(x,&localSize);CHKERRQ(ierr);
3530     ierr = VecGetArrayRead(x,&xarray);CHKERRQ(ierr);
3531     ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
3532     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);CHKERRQ(ierr);
3533   } else {
3534     xglob = x;
3535   }
3536   ierr = VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));CHKERRQ(ierr);
3537   if (size > 1) {
3538     ierr = VecDestroy(&xglob);CHKERRQ(ierr);
3539     ierr = VecRestoreArrayRead(x,&xarray);CHKERRQ(ierr);
3540   }
3541   ierr = VecDestroy(&x);CHKERRQ(ierr);
3542   PetscFunctionReturn(0);
3543 }
3544 
3545 /*@
3546   DMGetSection - Get the PetscSection encoding the local data layout for the DM.
3547 
3548   Input Parameter:
3549 . dm - The DM
3550 
3551   Output Parameter:
3552 . section - The PetscSection
3553 
3554   Options Database Keys:
3555 . -dm_petscsection_view - View the Section created by the DM
3556 
3557   Level: intermediate
3558 
3559   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3560 
3561 .seealso: DMSetSection(), DMGetGlobalSection()
3562 @*/
3563 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3564 {
3565   PetscErrorCode ierr;
3566 
3567   PetscFunctionBegin;
3568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3569   PetscValidPointer(section, 2);
3570   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3571     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3572     if (dm->defaultSection) {ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);}
3573   }
3574   *section = dm->defaultSection;
3575   PetscFunctionReturn(0);
3576 }
3577 
3578 /*@
3579   DMSetSection - Set the PetscSection encoding the local data layout for the DM.
3580 
3581   Input Parameters:
3582 + dm - The DM
3583 - section - The PetscSection
3584 
3585   Level: intermediate
3586 
3587   Note: Any existing Section will be destroyed
3588 
3589 .seealso: DMSetSection(), DMGetGlobalSection()
3590 @*/
3591 PetscErrorCode DMSetSection(DM dm, PetscSection section)
3592 {
3593   PetscInt       numFields = 0;
3594   PetscInt       f;
3595   PetscErrorCode ierr;
3596 
3597   PetscFunctionBegin;
3598   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3599   if (section) {
3600     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3601     ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3602   }
3603   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3604   dm->defaultSection = section;
3605   if (section) {ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);}
3606   if (numFields) {
3607     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3608     for (f = 0; f < numFields; ++f) {
3609       PetscObject disc;
3610       const char *name;
3611 
3612       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3613       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3614       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3615     }
3616   }
3617   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
3618   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3619   PetscFunctionReturn(0);
3620 }
3621 
3622 /*@
3623   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3624 
3625   not collective
3626 
3627   Input Parameter:
3628 . dm - The DM
3629 
3630   Output Parameter:
3631 + 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.
3632 - 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.
3633 
3634   Level: advanced
3635 
3636   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3637 
3638 .seealso: DMSetDefaultConstraints()
3639 @*/
3640 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3641 {
3642   PetscErrorCode ierr;
3643 
3644   PetscFunctionBegin;
3645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3646   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3647   if (section) {*section = dm->defaultConstraintSection;}
3648   if (mat) {*mat = dm->defaultConstraintMat;}
3649   PetscFunctionReturn(0);
3650 }
3651 
3652 /*@
3653   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3654 
3655   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().
3656 
3657   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.
3658 
3659   collective on dm
3660 
3661   Input Parameters:
3662 + dm - The DM
3663 + 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).
3664 - 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).
3665 
3666   Level: advanced
3667 
3668   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3669 
3670 .seealso: DMGetDefaultConstraints()
3671 @*/
3672 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3673 {
3674   PetscMPIInt result;
3675   PetscErrorCode ierr;
3676 
3677   PetscFunctionBegin;
3678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3679   if (section) {
3680     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3681     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3682     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3683   }
3684   if (mat) {
3685     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3686     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3687     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3688   }
3689   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3690   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3691   dm->defaultConstraintSection = section;
3692   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3693   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3694   dm->defaultConstraintMat = mat;
3695   PetscFunctionReturn(0);
3696 }
3697 
3698 #if defined(PETSC_USE_DEBUG)
3699 /*
3700   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
3701 
3702   Input Parameters:
3703 + dm - The DM
3704 . localSection - PetscSection describing the local data layout
3705 - globalSection - PetscSection describing the global data layout
3706 
3707   Level: intermediate
3708 
3709 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3710 */
3711 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3712 {
3713   MPI_Comm        comm;
3714   PetscLayout     layout;
3715   const PetscInt *ranges;
3716   PetscInt        pStart, pEnd, p, nroots;
3717   PetscMPIInt     size, rank;
3718   PetscBool       valid = PETSC_TRUE, gvalid;
3719   PetscErrorCode  ierr;
3720 
3721   PetscFunctionBegin;
3722   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3724   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3725   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3726   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3727   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3728   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3729   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3730   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3731   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3732   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3733   for (p = pStart; p < pEnd; ++p) {
3734     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
3735 
3736     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3737     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3738     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3739     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3740     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3741     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3742     if (!gdof) continue; /* Censored point */
3743     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;}
3744     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;}
3745     if (gdof < 0) {
3746       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3747       for (d = 0; d < gsize; ++d) {
3748         PetscInt offset = -(goff+1) + d, r;
3749 
3750         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3751         if (r < 0) r = -(r+2);
3752         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;}
3753       }
3754     }
3755   }
3756   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3757   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
3758   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
3759   if (!gvalid) {
3760     ierr = DMView(dm, NULL);CHKERRQ(ierr);
3761     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3762   }
3763   PetscFunctionReturn(0);
3764 }
3765 #endif
3766 
3767 /*@
3768   DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3769 
3770   Collective on DM
3771 
3772   Input Parameter:
3773 . dm - The DM
3774 
3775   Output Parameter:
3776 . section - The PetscSection
3777 
3778   Level: intermediate
3779 
3780   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3781 
3782 .seealso: DMSetSection(), DMGetSection()
3783 @*/
3784 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
3785 {
3786   PetscErrorCode ierr;
3787 
3788   PetscFunctionBegin;
3789   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3790   PetscValidPointer(section, 2);
3791   if (!dm->defaultGlobalSection) {
3792     PetscSection s;
3793 
3794     ierr = DMGetSection(dm, &s);CHKERRQ(ierr);
3795     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3796     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3797     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3798     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3799     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3800     ierr = PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");CHKERRQ(ierr);
3801   }
3802   *section = dm->defaultGlobalSection;
3803   PetscFunctionReturn(0);
3804 }
3805 
3806 /*@
3807   DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3808 
3809   Input Parameters:
3810 + dm - The DM
3811 - section - The PetscSection, or NULL
3812 
3813   Level: intermediate
3814 
3815   Note: Any existing Section will be destroyed
3816 
3817 .seealso: DMGetGlobalSection(), DMSetSection()
3818 @*/
3819 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
3820 {
3821   PetscErrorCode ierr;
3822 
3823   PetscFunctionBegin;
3824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3825   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3826   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3827   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3828   dm->defaultGlobalSection = section;
3829 #if defined(PETSC_USE_DEBUG)
3830   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);CHKERRQ(ierr);}
3831 #endif
3832   PetscFunctionReturn(0);
3833 }
3834 
3835 /*@
3836   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3837   it is created from the default PetscSection layouts in the DM.
3838 
3839   Input Parameter:
3840 . dm - The DM
3841 
3842   Output Parameter:
3843 . sf - The PetscSF
3844 
3845   Level: intermediate
3846 
3847   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3848 
3849 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3850 @*/
3851 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3852 {
3853   PetscInt       nroots;
3854   PetscErrorCode ierr;
3855 
3856   PetscFunctionBegin;
3857   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3858   PetscValidPointer(sf, 2);
3859   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3860   if (nroots < 0) {
3861     PetscSection section, gSection;
3862 
3863     ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
3864     if (section) {
3865       ierr = DMGetGlobalSection(dm, &gSection);CHKERRQ(ierr);
3866       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3867     } else {
3868       *sf = NULL;
3869       PetscFunctionReturn(0);
3870     }
3871   }
3872   *sf = dm->defaultSF;
3873   PetscFunctionReturn(0);
3874 }
3875 
3876 /*@
3877   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3878 
3879   Input Parameters:
3880 + dm - The DM
3881 - sf - The PetscSF
3882 
3883   Level: intermediate
3884 
3885   Note: Any previous SF is destroyed
3886 
3887 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3888 @*/
3889 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3890 {
3891   PetscErrorCode ierr;
3892 
3893   PetscFunctionBegin;
3894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3895   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3896   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3897   dm->defaultSF = sf;
3898   PetscFunctionReturn(0);
3899 }
3900 
3901 /*@C
3902   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3903   describing the data layout.
3904 
3905   Input Parameters:
3906 + dm - The DM
3907 . localSection - PetscSection describing the local data layout
3908 - globalSection - PetscSection describing the global data layout
3909 
3910   Level: intermediate
3911 
3912 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3913 @*/
3914 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3915 {
3916   MPI_Comm       comm;
3917   PetscLayout    layout;
3918   const PetscInt *ranges;
3919   PetscInt       *local;
3920   PetscSFNode    *remote;
3921   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3922   PetscMPIInt    size, rank;
3923   PetscErrorCode ierr;
3924 
3925   PetscFunctionBegin;
3926   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3927   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3928   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3929   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3930   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3931   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3932   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3933   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3934   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3935   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3936   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3937   for (p = pStart; p < pEnd; ++p) {
3938     PetscInt gdof, gcdof;
3939 
3940     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3941     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3942     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));
3943     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3944   }
3945   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3946   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3947   for (p = pStart, l = 0; p < pEnd; ++p) {
3948     const PetscInt *cind;
3949     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3950 
3951     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3952     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3953     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3954     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3955     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3956     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3957     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3958     if (!gdof) continue; /* Censored point */
3959     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3960     if (gsize != dof-cdof) {
3961       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);
3962       cdof = 0; /* Ignore constraints */
3963     }
3964     for (d = 0, c = 0; d < dof; ++d) {
3965       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3966       local[l+d-c] = off+d;
3967     }
3968     if (gdof < 0) {
3969       for (d = 0; d < gsize; ++d, ++l) {
3970         PetscInt offset = -(goff+1) + d, r;
3971 
3972         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3973         if (r < 0) r = -(r+2);
3974         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);
3975         remote[l].rank  = r;
3976         remote[l].index = offset - ranges[r];
3977       }
3978     } else {
3979       for (d = 0; d < gsize; ++d, ++l) {
3980         remote[l].rank  = rank;
3981         remote[l].index = goff+d - ranges[rank];
3982       }
3983     }
3984   }
3985   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3986   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3987   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3988   PetscFunctionReturn(0);
3989 }
3990 
3991 /*@
3992   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3993 
3994   Input Parameter:
3995 . dm - The DM
3996 
3997   Output Parameter:
3998 . sf - The PetscSF
3999 
4000   Level: intermediate
4001 
4002   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4003 
4004 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
4005 @*/
4006 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4007 {
4008   PetscFunctionBegin;
4009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4010   PetscValidPointer(sf, 2);
4011   *sf = dm->sf;
4012   PetscFunctionReturn(0);
4013 }
4014 
4015 /*@
4016   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4017 
4018   Input Parameters:
4019 + dm - The DM
4020 - sf - The PetscSF
4021 
4022   Level: intermediate
4023 
4024 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
4025 @*/
4026 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4027 {
4028   PetscErrorCode ierr;
4029 
4030   PetscFunctionBegin;
4031   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4032   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
4033   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
4034   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4035   dm->sf = sf;
4036   PetscFunctionReturn(0);
4037 }
4038 
4039 /*@
4040   DMGetDS - Get the PetscDS
4041 
4042   Input Parameter:
4043 . dm - The DM
4044 
4045   Output Parameter:
4046 . prob - The PetscDS
4047 
4048   Level: developer
4049 
4050 .seealso: DMSetDS()
4051 @*/
4052 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4053 {
4054   PetscFunctionBegin;
4055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4056   PetscValidPointer(prob, 2);
4057   *prob = dm->prob;
4058   PetscFunctionReturn(0);
4059 }
4060 
4061 /*@
4062   DMSetDS - Set the PetscDS
4063 
4064   Input Parameters:
4065 + dm - The DM
4066 - prob - The PetscDS
4067 
4068   Level: developer
4069 
4070 .seealso: DMGetDS()
4071 @*/
4072 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
4073 {
4074   PetscInt       dimEmbed;
4075   PetscErrorCode ierr;
4076 
4077   PetscFunctionBegin;
4078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4079   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
4080   ierr = PetscObjectReference((PetscObject) prob);CHKERRQ(ierr);
4081   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
4082   dm->prob = prob;
4083   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
4084   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
4085   PetscFunctionReturn(0);
4086 }
4087 
4088 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4089 {
4090   PetscErrorCode ierr;
4091 
4092   PetscFunctionBegin;
4093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4094   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
4095   PetscFunctionReturn(0);
4096 }
4097 
4098 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4099 {
4100   PetscInt       Nf, f;
4101   PetscErrorCode ierr;
4102 
4103   PetscFunctionBegin;
4104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4105   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
4106   for (f = Nf; f < numFields; ++f) {
4107     PetscContainer obj;
4108 
4109     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4110     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
4111     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4112   }
4113   PetscFunctionReturn(0);
4114 }
4115 
4116 /*@
4117   DMGetField - Return the discretization object for a given DM field
4118 
4119   Not collective
4120 
4121   Input Parameters:
4122 + dm - The DM
4123 - f  - The field number
4124 
4125   Output Parameter:
4126 . field - The discretization object
4127 
4128   Level: developer
4129 
4130 .seealso: DMSetField()
4131 @*/
4132 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
4133 {
4134   PetscErrorCode ierr;
4135 
4136   PetscFunctionBegin;
4137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4138   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
4139   PetscFunctionReturn(0);
4140 }
4141 
4142 /*@
4143   DMSetField - Set the discretization object for a given DM field
4144 
4145   Logically collective on DM
4146 
4147   Input Parameters:
4148 + dm - The DM
4149 . f  - The field number
4150 - field - The discretization object
4151 
4152   Level: developer
4153 
4154 .seealso: DMGetField()
4155 @*/
4156 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
4157 {
4158   PetscErrorCode ierr;
4159 
4160   PetscFunctionBegin;
4161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4162   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
4163   PetscFunctionReturn(0);
4164 }
4165 
4166 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
4167 {
4168   DM dm_coord,dmc_coord;
4169   PetscErrorCode ierr;
4170   Vec coords,ccoords;
4171   Mat inject;
4172   PetscFunctionBegin;
4173   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
4174   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
4175   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
4176   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
4177   if (coords && !ccoords) {
4178     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
4179     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
4180     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
4181     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
4182     ierr = MatDestroy(&inject);CHKERRQ(ierr);
4183     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
4184     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
4185   }
4186   PetscFunctionReturn(0);
4187 }
4188 
4189 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
4190 {
4191   DM dm_coord,subdm_coord;
4192   PetscErrorCode ierr;
4193   Vec coords,ccoords,clcoords;
4194   VecScatter *scat_i,*scat_g;
4195   PetscFunctionBegin;
4196   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
4197   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
4198   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
4199   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
4200   if (coords && !ccoords) {
4201     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
4202     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
4203     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
4204     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
4205     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
4206     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4207     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4208     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4209     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4210     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
4211     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
4212     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
4213     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
4214     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
4215     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
4216     ierr = PetscFree(scat_i);CHKERRQ(ierr);
4217     ierr = PetscFree(scat_g);CHKERRQ(ierr);
4218   }
4219   PetscFunctionReturn(0);
4220 }
4221 
4222 /*@
4223   DMGetDimension - Return the topological dimension of the DM
4224 
4225   Not collective
4226 
4227   Input Parameter:
4228 . dm - The DM
4229 
4230   Output Parameter:
4231 . dim - The topological dimension
4232 
4233   Level: beginner
4234 
4235 .seealso: DMSetDimension(), DMCreate()
4236 @*/
4237 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
4238 {
4239   PetscFunctionBegin;
4240   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4241   PetscValidPointer(dim, 2);
4242   *dim = dm->dim;
4243   PetscFunctionReturn(0);
4244 }
4245 
4246 /*@
4247   DMSetDimension - Set the topological dimension of the DM
4248 
4249   Collective on dm
4250 
4251   Input Parameters:
4252 + dm - The DM
4253 - dim - The topological dimension
4254 
4255   Level: beginner
4256 
4257 .seealso: DMGetDimension(), DMCreate()
4258 @*/
4259 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
4260 {
4261   PetscErrorCode ierr;
4262 
4263   PetscFunctionBegin;
4264   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4265   PetscValidLogicalCollectiveInt(dm, dim, 2);
4266   dm->dim = dim;
4267   if (dm->prob->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dim);CHKERRQ(ierr);}
4268   PetscFunctionReturn(0);
4269 }
4270 
4271 /*@
4272   DMGetDimPoints - Get the half-open interval for all points of a given dimension
4273 
4274   Collective on DM
4275 
4276   Input Parameters:
4277 + dm - the DM
4278 - dim - the dimension
4279 
4280   Output Parameters:
4281 + pStart - The first point of the given dimension
4282 . pEnd - The first point following points of the given dimension
4283 
4284   Note:
4285   The points are vertices in the Hasse diagram encoding the topology. This is explained in
4286   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
4287   then the interval is empty.
4288 
4289   Level: intermediate
4290 
4291 .keywords: point, Hasse Diagram, dimension
4292 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
4293 @*/
4294 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4295 {
4296   PetscInt       d;
4297   PetscErrorCode ierr;
4298 
4299   PetscFunctionBegin;
4300   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4301   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
4302   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
4303   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
4304   PetscFunctionReturn(0);
4305 }
4306 
4307 /*@
4308   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
4309 
4310   Collective on DM
4311 
4312   Input Parameters:
4313 + dm - the DM
4314 - c - coordinate vector
4315 
4316   Notes:
4317   The coordinates do include those for ghost points, which are in the local vector.
4318 
4319   The vector c should be destroyed by the caller.
4320 
4321   Level: intermediate
4322 
4323 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4324 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4325 @*/
4326 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4327 {
4328   PetscErrorCode ierr;
4329 
4330   PetscFunctionBegin;
4331   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4332   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4333   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4334   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4335   dm->coordinates = c;
4336   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4337   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4338   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
4339   PetscFunctionReturn(0);
4340 }
4341 
4342 /*@
4343   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
4344 
4345   Collective on DM
4346 
4347    Input Parameters:
4348 +  dm - the DM
4349 -  c - coordinate vector
4350 
4351   Notes:
4352   The coordinates of ghost points can be set using DMSetCoordinates()
4353   followed by DMGetCoordinatesLocal(). This is intended to enable the
4354   setting of ghost coordinates outside of the domain.
4355 
4356   The vector c should be destroyed by the caller.
4357 
4358   Level: intermediate
4359 
4360 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4361 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4362 @*/
4363 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4364 {
4365   PetscErrorCode ierr;
4366 
4367   PetscFunctionBegin;
4368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4369   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
4370   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
4371   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
4372 
4373   dm->coordinatesLocal = c;
4374 
4375   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
4376   PetscFunctionReturn(0);
4377 }
4378 
4379 /*@
4380   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
4381 
4382   Not Collective
4383 
4384   Input Parameter:
4385 . dm - the DM
4386 
4387   Output Parameter:
4388 . c - global coordinate vector
4389 
4390   Note:
4391   This is a borrowed reference, so the user should NOT destroy this vector
4392 
4393   Each process has only the local coordinates (does NOT have the ghost coordinates).
4394 
4395   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4396   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4397 
4398   Level: intermediate
4399 
4400 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4401 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4402 @*/
4403 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4404 {
4405   PetscErrorCode ierr;
4406 
4407   PetscFunctionBegin;
4408   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4409   PetscValidPointer(c,2);
4410   if (!dm->coordinates && dm->coordinatesLocal) {
4411     DM cdm = NULL;
4412 
4413     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4414     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4415     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4416     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4417     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4418   }
4419   *c = dm->coordinates;
4420   PetscFunctionReturn(0);
4421 }
4422 
4423 /*@
4424   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4425 
4426   Collective on DM
4427 
4428   Input Parameter:
4429 . dm - the DM
4430 
4431   Output Parameter:
4432 . c - coordinate vector
4433 
4434   Note:
4435   This is a borrowed reference, so the user should NOT destroy this vector
4436 
4437   Each process has the local and ghost coordinates
4438 
4439   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4440   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4441 
4442   Level: intermediate
4443 
4444 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4445 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4446 @*/
4447 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4448 {
4449   PetscErrorCode ierr;
4450 
4451   PetscFunctionBegin;
4452   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4453   PetscValidPointer(c,2);
4454   if (!dm->coordinatesLocal && dm->coordinates) {
4455     DM cdm = NULL;
4456 
4457     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4458     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4459     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4460     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4461     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4462   }
4463   *c = dm->coordinatesLocal;
4464   PetscFunctionReturn(0);
4465 }
4466 
4467 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
4468 {
4469   PetscErrorCode ierr;
4470 
4471   PetscFunctionBegin;
4472   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4473   PetscValidPointer(field,2);
4474   if (!dm->coordinateField) {
4475     if (dm->ops->createcoordinatefield) {
4476       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
4477     }
4478   }
4479   *field = dm->coordinateField;
4480   PetscFunctionReturn(0);
4481 }
4482 
4483 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
4484 {
4485   PetscErrorCode ierr;
4486 
4487   PetscFunctionBegin;
4488   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4489   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
4490   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
4491   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
4492   dm->coordinateField = field;
4493   PetscFunctionReturn(0);
4494 }
4495 
4496 /*@
4497   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4498 
4499   Collective on DM
4500 
4501   Input Parameter:
4502 . dm - the DM
4503 
4504   Output Parameter:
4505 . cdm - coordinate DM
4506 
4507   Level: intermediate
4508 
4509 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4510 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4511 @*/
4512 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4513 {
4514   PetscErrorCode ierr;
4515 
4516   PetscFunctionBegin;
4517   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4518   PetscValidPointer(cdm,2);
4519   if (!dm->coordinateDM) {
4520     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4521     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4522   }
4523   *cdm = dm->coordinateDM;
4524   PetscFunctionReturn(0);
4525 }
4526 
4527 /*@
4528   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4529 
4530   Logically Collective on DM
4531 
4532   Input Parameters:
4533 + dm - the DM
4534 - cdm - coordinate DM
4535 
4536   Level: intermediate
4537 
4538 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4539 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4540 @*/
4541 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4542 {
4543   PetscErrorCode ierr;
4544 
4545   PetscFunctionBegin;
4546   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4547   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4548   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4549   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4550   dm->coordinateDM = cdm;
4551   PetscFunctionReturn(0);
4552 }
4553 
4554 /*@
4555   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4556 
4557   Not Collective
4558 
4559   Input Parameter:
4560 . dm - The DM object
4561 
4562   Output Parameter:
4563 . dim - The embedding dimension
4564 
4565   Level: intermediate
4566 
4567 .keywords: mesh, coordinates
4568 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4569 @*/
4570 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4571 {
4572   PetscFunctionBegin;
4573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4574   PetscValidPointer(dim, 2);
4575   if (dm->dimEmbed == PETSC_DEFAULT) {
4576     dm->dimEmbed = dm->dim;
4577   }
4578   *dim = dm->dimEmbed;
4579   PetscFunctionReturn(0);
4580 }
4581 
4582 /*@
4583   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4584 
4585   Not Collective
4586 
4587   Input Parameters:
4588 + dm  - The DM object
4589 - dim - The embedding dimension
4590 
4591   Level: intermediate
4592 
4593 .keywords: mesh, coordinates
4594 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4595 @*/
4596 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4597 {
4598   PetscErrorCode ierr;
4599 
4600   PetscFunctionBegin;
4601   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4602   dm->dimEmbed = dim;
4603   ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);CHKERRQ(ierr);
4604   PetscFunctionReturn(0);
4605 }
4606 
4607 /*@
4608   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4609 
4610   Not Collective
4611 
4612   Input Parameter:
4613 . dm - The DM object
4614 
4615   Output Parameter:
4616 . section - The PetscSection object
4617 
4618   Level: intermediate
4619 
4620 .keywords: mesh, coordinates
4621 .seealso: DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4622 @*/
4623 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4624 {
4625   DM             cdm;
4626   PetscErrorCode ierr;
4627 
4628   PetscFunctionBegin;
4629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4630   PetscValidPointer(section, 2);
4631   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4632   ierr = DMGetSection(cdm, section);CHKERRQ(ierr);
4633   PetscFunctionReturn(0);
4634 }
4635 
4636 /*@
4637   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4638 
4639   Not Collective
4640 
4641   Input Parameters:
4642 + dm      - The DM object
4643 . dim     - The embedding dimension, or PETSC_DETERMINE
4644 - section - The PetscSection object
4645 
4646   Level: intermediate
4647 
4648 .keywords: mesh, coordinates
4649 .seealso: DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4650 @*/
4651 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4652 {
4653   DM             cdm;
4654   PetscErrorCode ierr;
4655 
4656   PetscFunctionBegin;
4657   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4658   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4659   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4660   ierr = DMSetSection(cdm, section);CHKERRQ(ierr);
4661   if (dim == PETSC_DETERMINE) {
4662     PetscInt d = PETSC_DEFAULT;
4663     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4664 
4665     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4666     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4667     pStart = PetscMax(vStart, pStart);
4668     pEnd   = PetscMin(vEnd, pEnd);
4669     for (v = pStart; v < pEnd; ++v) {
4670       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4671       if (dd) {d = dd; break;}
4672     }
4673     if (d < 0) d = PETSC_DEFAULT;
4674     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4675   }
4676   PetscFunctionReturn(0);
4677 }
4678 
4679 /*@C
4680   DMGetPeriodicity - Get the description of mesh periodicity
4681 
4682   Input Parameters:
4683 . dm      - The DM object
4684 
4685   Output Parameters:
4686 + per     - Whether the DM is periodic or not
4687 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4688 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4689 - bd      - This describes the type of periodicity in each topological dimension
4690 
4691   Level: developer
4692 
4693 .seealso: DMGetPeriodicity()
4694 @*/
4695 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4696 {
4697   PetscFunctionBegin;
4698   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4699   if (per)     *per     = dm->periodic;
4700   if (L)       *L       = dm->L;
4701   if (maxCell) *maxCell = dm->maxCell;
4702   if (bd)      *bd      = dm->bdtype;
4703   PetscFunctionReturn(0);
4704 }
4705 
4706 /*@C
4707   DMSetPeriodicity - Set the description of mesh periodicity
4708 
4709   Input Parameters:
4710 + dm      - The DM object
4711 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4712 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4713 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4714 - bd      - This describes the type of periodicity in each topological dimension
4715 
4716   Level: developer
4717 
4718 .seealso: DMGetPeriodicity()
4719 @*/
4720 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4721 {
4722   PetscInt       dim, d;
4723   PetscErrorCode ierr;
4724 
4725   PetscFunctionBegin;
4726   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4727   PetscValidLogicalCollectiveBool(dm,per,2);
4728   if (maxCell) {
4729     PetscValidPointer(maxCell,3);
4730     PetscValidPointer(L,4);
4731     PetscValidPointer(bd,5);
4732   }
4733   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4734   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4735   if (maxCell) {
4736     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4737     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4738     dm->periodic = PETSC_TRUE;
4739   } else {
4740     dm->periodic = per;
4741   }
4742   PetscFunctionReturn(0);
4743 }
4744 
4745 /*@
4746   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.
4747 
4748   Input Parameters:
4749 + dm     - The DM
4750 . in     - The input coordinate point (dim numbers)
4751 - endpoint - Include the endpoint L_i
4752 
4753   Output Parameter:
4754 . out - The localized coordinate point
4755 
4756   Level: developer
4757 
4758 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4759 @*/
4760 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4761 {
4762   PetscInt       dim, d;
4763   PetscErrorCode ierr;
4764 
4765   PetscFunctionBegin;
4766   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4767   if (!dm->maxCell) {
4768     for (d = 0; d < dim; ++d) out[d] = in[d];
4769   } else {
4770     if (endpoint) {
4771       for (d = 0; d < dim; ++d) {
4772         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)) {
4773           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4774         } else {
4775           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4776         }
4777       }
4778     } else {
4779       for (d = 0; d < dim; ++d) {
4780         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4781       }
4782     }
4783   }
4784   PetscFunctionReturn(0);
4785 }
4786 
4787 /*
4788   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.
4789 
4790   Input Parameters:
4791 + dm     - The DM
4792 . dim    - The spatial dimension
4793 . anchor - The anchor point, the input point can be no more than maxCell away from it
4794 - in     - The input coordinate point (dim numbers)
4795 
4796   Output Parameter:
4797 . out - The localized coordinate point
4798 
4799   Level: developer
4800 
4801   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
4802 
4803 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4804 */
4805 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4806 {
4807   PetscInt d;
4808 
4809   PetscFunctionBegin;
4810   if (!dm->maxCell) {
4811     for (d = 0; d < dim; ++d) out[d] = in[d];
4812   } else {
4813     for (d = 0; d < dim; ++d) {
4814       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4815         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4816       } else {
4817         out[d] = in[d];
4818       }
4819     }
4820   }
4821   PetscFunctionReturn(0);
4822 }
4823 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4824 {
4825   PetscInt d;
4826 
4827   PetscFunctionBegin;
4828   if (!dm->maxCell) {
4829     for (d = 0; d < dim; ++d) out[d] = in[d];
4830   } else {
4831     for (d = 0; d < dim; ++d) {
4832       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4833         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4834       } else {
4835         out[d] = in[d];
4836       }
4837     }
4838   }
4839   PetscFunctionReturn(0);
4840 }
4841 
4842 /*
4843   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.
4844 
4845   Input Parameters:
4846 + dm     - The DM
4847 . dim    - The spatial dimension
4848 . anchor - The anchor point, the input point can be no more than maxCell away from it
4849 . in     - The input coordinate delta (dim numbers)
4850 - out    - The input coordinate point (dim numbers)
4851 
4852   Output Parameter:
4853 . out    - The localized coordinate in + out
4854 
4855   Level: developer
4856 
4857   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
4858 
4859 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4860 */
4861 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4862 {
4863   PetscInt d;
4864 
4865   PetscFunctionBegin;
4866   if (!dm->maxCell) {
4867     for (d = 0; d < dim; ++d) out[d] += in[d];
4868   } else {
4869     for (d = 0; d < dim; ++d) {
4870       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4871         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4872       } else {
4873         out[d] += in[d];
4874       }
4875     }
4876   }
4877   PetscFunctionReturn(0);
4878 }
4879 
4880 /*@
4881   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4882 
4883   Input Parameter:
4884 . dm - The DM
4885 
4886   Output Parameter:
4887   areLocalized - True if localized
4888 
4889   Level: developer
4890 
4891 .seealso: DMLocalizeCoordinates()
4892 @*/
4893 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4894 {
4895   DM             cdm;
4896   PetscSection   coordSection;
4897   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
4898   PetscBool      isPlex, alreadyLocalized;
4899   PetscErrorCode ierr;
4900 
4901   PetscFunctionBegin;
4902   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4903   PetscValidPointer(areLocalized, 2);
4904 
4905   *areLocalized = PETSC_FALSE;
4906   if (!dm->periodic) PetscFunctionReturn(0); /* This is a hideous optimization hack! */
4907 
4908   /* We need some generic way of refering to cells/vertices */
4909   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4910   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4911   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
4912   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4913 
4914   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4915   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
4916   alreadyLocalized = PETSC_FALSE;
4917   for (c = cStart; c < cEnd; ++c) {
4918     if (c < sStart || c >= sEnd) continue;
4919     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4920     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
4921   }
4922   ierr = MPIU_Allreduce(&alreadyLocalized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4923   PetscFunctionReturn(0);
4924 }
4925 
4926 
4927 /*@
4928   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
4929 
4930   Input Parameter:
4931 . dm - The DM
4932 
4933   Level: developer
4934 
4935 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4936 @*/
4937 PetscErrorCode DMLocalizeCoordinates(DM dm)
4938 {
4939   DM             cdm;
4940   PetscSection   coordSection, cSection;
4941   Vec            coordinates,  cVec;
4942   PetscScalar   *coords, *coords2, *anchor, *localized;
4943   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4944   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4945   PetscInt       maxHeight = 0, h;
4946   PetscInt       *pStart = NULL, *pEnd = NULL;
4947   PetscErrorCode ierr;
4948 
4949   PetscFunctionBegin;
4950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4951   if (!dm->periodic) PetscFunctionReturn(0);
4952   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
4953   if (alreadyLocalized) PetscFunctionReturn(0);
4954 
4955   /* We need some generic way of refering to cells/vertices */
4956   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4957   {
4958     PetscBool isplex;
4959 
4960     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4961     if (isplex) {
4962       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4963       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4964       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
4965       pEnd = &pStart[maxHeight + 1];
4966       newStart = vStart;
4967       newEnd   = vEnd;
4968       for (h = 0; h <= maxHeight; h++) {
4969         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4970         newStart = PetscMin(newStart,pStart[h]);
4971         newEnd   = PetscMax(newEnd,pEnd[h]);
4972       }
4973     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4974   }
4975   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4976   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
4977   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4978   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4979   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4980 
4981   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4982   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4983   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4984   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4985   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4986 
4987   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
4988   localized = &anchor[bs];
4989   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4990   for (h = 0; h <= maxHeight; h++) {
4991     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4992 
4993     for (c = cStart; c < cEnd; ++c) {
4994       PetscScalar *cellCoords = NULL;
4995       PetscInt     b;
4996 
4997       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4998       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4999       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5000       for (d = 0; d < dof/bs; ++d) {
5001         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
5002         for (b = 0; b < bs; b++) {
5003           if (cellCoords[d*bs + b] != localized[b]) break;
5004         }
5005         if (b < bs) break;
5006       }
5007       if (d < dof/bs) {
5008         if (c >= sStart && c < sEnd) {
5009           PetscInt cdof;
5010 
5011           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
5012           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
5013         }
5014         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
5015         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
5016       }
5017       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5018     }
5019   }
5020   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
5021   if (alreadyLocalizedGlobal) {
5022     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5023     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5024     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5025     PetscFunctionReturn(0);
5026   }
5027   for (v = vStart; v < vEnd; ++v) {
5028     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5029     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
5030     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
5031   }
5032   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
5033   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
5034   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
5035   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
5036   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
5037   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
5038   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
5039   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5040   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
5041   for (v = vStart; v < vEnd; ++v) {
5042     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5043     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5044     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
5045     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
5046   }
5047   for (h = 0; h <= maxHeight; h++) {
5048     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5049 
5050     for (c = cStart; c < cEnd; ++c) {
5051       PetscScalar *cellCoords = NULL;
5052       PetscInt     b, cdof;
5053 
5054       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
5055       if (!cdof) continue;
5056       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5057       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
5058       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5059       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
5060       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5061     }
5062   }
5063   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5064   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5065   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5066   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
5067   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
5068   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
5069   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
5070   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5071   PetscFunctionReturn(0);
5072 }
5073 
5074 /*@
5075   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
5076 
5077   Collective on Vec v (see explanation below)
5078 
5079   Input Parameters:
5080 + dm - The DM
5081 . v - The Vec of points
5082 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
5083 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
5084 
5085   Output Parameter:
5086 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
5087 - cells - The PetscSF containing the ranks and local indices of the containing points.
5088 
5089 
5090   Level: developer
5091 
5092   Notes:
5093   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
5094   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
5095 
5096   If *cellSF is NULL on input, a PetscSF will be created.
5097   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
5098 
5099   An array that maps each point to its containing cell can be obtained with
5100 
5101 $    const PetscSFNode *cells;
5102 $    PetscInt           nFound;
5103 $    const PetscInt    *found;
5104 $
5105 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
5106 
5107   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
5108   the index of the cell in its rank's local numbering.
5109 
5110 .keywords: point location, mesh
5111 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
5112 @*/
5113 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
5114 {
5115   PetscErrorCode ierr;
5116 
5117   PetscFunctionBegin;
5118   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5119   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
5120   PetscValidPointer(cellSF,4);
5121   if (*cellSF) {
5122     PetscMPIInt result;
5123 
5124     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
5125     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
5126     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
5127   } else {
5128     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
5129   }
5130   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5131   if (dm->ops->locatepoints) {
5132     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
5133   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
5134   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5135   PetscFunctionReturn(0);
5136 }
5137 
5138 /*@
5139   DMGetOutputDM - Retrieve the DM associated with the layout for output
5140 
5141   Input Parameter:
5142 . dm - The original DM
5143 
5144   Output Parameter:
5145 . odm - The DM which provides the layout for output
5146 
5147   Level: intermediate
5148 
5149 .seealso: VecView(), DMGetGlobalSection()
5150 @*/
5151 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
5152 {
5153   PetscSection   section;
5154   PetscBool      hasConstraints, ghasConstraints;
5155   PetscErrorCode ierr;
5156 
5157   PetscFunctionBegin;
5158   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5159   PetscValidPointer(odm,2);
5160   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
5161   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
5162   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
5163   if (!ghasConstraints) {
5164     *odm = dm;
5165     PetscFunctionReturn(0);
5166   }
5167   if (!dm->dmBC) {
5168     PetscDS      ds;
5169     PetscSection newSection, gsection;
5170     PetscSF      sf;
5171 
5172     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
5173     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5174     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
5175     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
5176     ierr = DMSetSection(dm->dmBC, newSection);CHKERRQ(ierr);
5177     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
5178     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
5179     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
5180     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
5181     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
5182   }
5183   *odm = dm->dmBC;
5184   PetscFunctionReturn(0);
5185 }
5186 
5187 /*@
5188   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
5189 
5190   Input Parameter:
5191 . dm - The original DM
5192 
5193   Output Parameters:
5194 + num - The output sequence number
5195 - val - The output sequence value
5196 
5197   Level: intermediate
5198 
5199   Note: This is intended for output that should appear in sequence, for instance
5200   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5201 
5202 .seealso: VecView()
5203 @*/
5204 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
5205 {
5206   PetscFunctionBegin;
5207   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5208   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
5209   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
5210   PetscFunctionReturn(0);
5211 }
5212 
5213 /*@
5214   DMSetOutputSequenceNumber - Set the sequence number/value for output
5215 
5216   Input Parameters:
5217 + dm - The original DM
5218 . num - The output sequence number
5219 - val - The output sequence value
5220 
5221   Level: intermediate
5222 
5223   Note: This is intended for output that should appear in sequence, for instance
5224   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5225 
5226 .seealso: VecView()
5227 @*/
5228 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5229 {
5230   PetscFunctionBegin;
5231   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5232   dm->outputSequenceNum = num;
5233   dm->outputSequenceVal = val;
5234   PetscFunctionReturn(0);
5235 }
5236 
5237 /*@C
5238   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
5239 
5240   Input Parameters:
5241 + dm   - The original DM
5242 . name - The sequence name
5243 - num  - The output sequence number
5244 
5245   Output Parameter:
5246 . val  - The output sequence value
5247 
5248   Level: intermediate
5249 
5250   Note: This is intended for output that should appear in sequence, for instance
5251   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5252 
5253 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5254 @*/
5255 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5256 {
5257   PetscBool      ishdf5;
5258   PetscErrorCode ierr;
5259 
5260   PetscFunctionBegin;
5261   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5262   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
5263   PetscValidPointer(val,4);
5264   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
5265   if (ishdf5) {
5266 #if defined(PETSC_HAVE_HDF5)
5267     PetscScalar value;
5268 
5269     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
5270     *val = PetscRealPart(value);
5271 #endif
5272   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5273   PetscFunctionReturn(0);
5274 }
5275 
5276 /*@
5277   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
5278 
5279   Not collective
5280 
5281   Input Parameter:
5282 . dm - The DM
5283 
5284   Output Parameter:
5285 . useNatural - The flag to build the mapping to a natural order during distribution
5286 
5287   Level: beginner
5288 
5289 .seealso: DMSetUseNatural(), DMCreate()
5290 @*/
5291 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5292 {
5293   PetscFunctionBegin;
5294   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5295   PetscValidPointer(useNatural, 2);
5296   *useNatural = dm->useNatural;
5297   PetscFunctionReturn(0);
5298 }
5299 
5300 /*@
5301   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
5302 
5303   Collective on dm
5304 
5305   Input Parameters:
5306 + dm - The DM
5307 - useNatural - The flag to build the mapping to a natural order during distribution
5308 
5309   Level: beginner
5310 
5311 .seealso: DMGetUseNatural(), DMCreate()
5312 @*/
5313 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5314 {
5315   PetscFunctionBegin;
5316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5317   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
5318   dm->useNatural = useNatural;
5319   PetscFunctionReturn(0);
5320 }
5321 
5322 
5323 /*@C
5324   DMCreateLabel - Create a label of the given name if it does not already exist
5325 
5326   Not Collective
5327 
5328   Input Parameters:
5329 + dm   - The DM object
5330 - name - The label name
5331 
5332   Level: intermediate
5333 
5334 .keywords: mesh
5335 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5336 @*/
5337 PetscErrorCode DMCreateLabel(DM dm, const char name[])
5338 {
5339   DMLabelLink    next  = dm->labels->next;
5340   PetscBool      flg   = PETSC_FALSE;
5341   PetscErrorCode ierr;
5342 
5343   PetscFunctionBegin;
5344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5345   PetscValidCharPointer(name, 2);
5346   while (next) {
5347     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5348     if (flg) break;
5349     next = next->next;
5350   }
5351   if (!flg) {
5352     DMLabelLink tmpLabel;
5353 
5354     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5355     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
5356     tmpLabel->output = PETSC_TRUE;
5357     tmpLabel->next   = dm->labels->next;
5358     dm->labels->next = tmpLabel;
5359   }
5360   PetscFunctionReturn(0);
5361 }
5362 
5363 /*@C
5364   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
5365 
5366   Not Collective
5367 
5368   Input Parameters:
5369 + dm   - The DM object
5370 . name - The label name
5371 - point - The mesh point
5372 
5373   Output Parameter:
5374 . value - The label value for this point, or -1 if the point is not in the label
5375 
5376   Level: beginner
5377 
5378 .keywords: mesh
5379 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5380 @*/
5381 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5382 {
5383   DMLabel        label;
5384   PetscErrorCode ierr;
5385 
5386   PetscFunctionBegin;
5387   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5388   PetscValidCharPointer(name, 2);
5389   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5390   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5391   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
5392   PetscFunctionReturn(0);
5393 }
5394 
5395 /*@C
5396   DMSetLabelValue - Add a point to a Sieve Label with given value
5397 
5398   Not Collective
5399 
5400   Input Parameters:
5401 + dm   - The DM object
5402 . name - The label name
5403 . point - The mesh point
5404 - value - The label value for this point
5405 
5406   Output Parameter:
5407 
5408   Level: beginner
5409 
5410 .keywords: mesh
5411 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5412 @*/
5413 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5414 {
5415   DMLabel        label;
5416   PetscErrorCode ierr;
5417 
5418   PetscFunctionBegin;
5419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5420   PetscValidCharPointer(name, 2);
5421   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5422   if (!label) {
5423     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
5424     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5425   }
5426   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
5427   PetscFunctionReturn(0);
5428 }
5429 
5430 /*@C
5431   DMClearLabelValue - Remove a point from a Sieve Label with given value
5432 
5433   Not Collective
5434 
5435   Input Parameters:
5436 + dm   - The DM object
5437 . name - The label name
5438 . point - The mesh point
5439 - value - The label value for this point
5440 
5441   Output Parameter:
5442 
5443   Level: beginner
5444 
5445 .keywords: mesh
5446 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5447 @*/
5448 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5449 {
5450   DMLabel        label;
5451   PetscErrorCode ierr;
5452 
5453   PetscFunctionBegin;
5454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5455   PetscValidCharPointer(name, 2);
5456   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5457   if (!label) PetscFunctionReturn(0);
5458   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5459   PetscFunctionReturn(0);
5460 }
5461 
5462 /*@C
5463   DMGetLabelSize - Get the number of different integer ids in a Label
5464 
5465   Not Collective
5466 
5467   Input Parameters:
5468 + dm   - The DM object
5469 - name - The label name
5470 
5471   Output Parameter:
5472 . size - The number of different integer ids, or 0 if the label does not exist
5473 
5474   Level: beginner
5475 
5476 .keywords: mesh
5477 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5478 @*/
5479 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5480 {
5481   DMLabel        label;
5482   PetscErrorCode ierr;
5483 
5484   PetscFunctionBegin;
5485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5486   PetscValidCharPointer(name, 2);
5487   PetscValidPointer(size, 3);
5488   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5489   *size = 0;
5490   if (!label) PetscFunctionReturn(0);
5491   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5492   PetscFunctionReturn(0);
5493 }
5494 
5495 /*@C
5496   DMGetLabelIdIS - Get the integer ids in a label
5497 
5498   Not Collective
5499 
5500   Input Parameters:
5501 + mesh - The DM object
5502 - name - The label name
5503 
5504   Output Parameter:
5505 . ids - The integer ids, or NULL if the label does not exist
5506 
5507   Level: beginner
5508 
5509 .keywords: mesh
5510 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5511 @*/
5512 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5513 {
5514   DMLabel        label;
5515   PetscErrorCode ierr;
5516 
5517   PetscFunctionBegin;
5518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5519   PetscValidCharPointer(name, 2);
5520   PetscValidPointer(ids, 3);
5521   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5522   *ids = NULL;
5523  if (label) {
5524     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5525   } else {
5526     /* returning an empty IS */
5527     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
5528   }
5529   PetscFunctionReturn(0);
5530 }
5531 
5532 /*@C
5533   DMGetStratumSize - Get the number of points in a label stratum
5534 
5535   Not Collective
5536 
5537   Input Parameters:
5538 + dm - The DM object
5539 . name - The label name
5540 - value - The stratum value
5541 
5542   Output Parameter:
5543 . size - The stratum size
5544 
5545   Level: beginner
5546 
5547 .keywords: mesh
5548 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5549 @*/
5550 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5551 {
5552   DMLabel        label;
5553   PetscErrorCode ierr;
5554 
5555   PetscFunctionBegin;
5556   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5557   PetscValidCharPointer(name, 2);
5558   PetscValidPointer(size, 4);
5559   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5560   *size = 0;
5561   if (!label) PetscFunctionReturn(0);
5562   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5563   PetscFunctionReturn(0);
5564 }
5565 
5566 /*@C
5567   DMGetStratumIS - Get the points in a label stratum
5568 
5569   Not Collective
5570 
5571   Input Parameters:
5572 + dm - The DM object
5573 . name - The label name
5574 - value - The stratum value
5575 
5576   Output Parameter:
5577 . points - The stratum points, or NULL if the label does not exist or does not have that value
5578 
5579   Level: beginner
5580 
5581 .keywords: mesh
5582 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5583 @*/
5584 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5585 {
5586   DMLabel        label;
5587   PetscErrorCode ierr;
5588 
5589   PetscFunctionBegin;
5590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5591   PetscValidCharPointer(name, 2);
5592   PetscValidPointer(points, 4);
5593   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5594   *points = NULL;
5595   if (!label) PetscFunctionReturn(0);
5596   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5597   PetscFunctionReturn(0);
5598 }
5599 
5600 /*@C
5601   DMSetStratumIS - Set the points in a label stratum
5602 
5603   Not Collective
5604 
5605   Input Parameters:
5606 + dm - The DM object
5607 . name - The label name
5608 . value - The stratum value
5609 - points - The stratum points
5610 
5611   Level: beginner
5612 
5613 .keywords: mesh
5614 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5615 @*/
5616 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5617 {
5618   DMLabel        label;
5619   PetscErrorCode ierr;
5620 
5621   PetscFunctionBegin;
5622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5623   PetscValidCharPointer(name, 2);
5624   PetscValidPointer(points, 4);
5625   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5626   if (!label) PetscFunctionReturn(0);
5627   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5628   PetscFunctionReturn(0);
5629 }
5630 
5631 /*@C
5632   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5633 
5634   Not Collective
5635 
5636   Input Parameters:
5637 + dm   - The DM object
5638 . name - The label name
5639 - value - The label value for this point
5640 
5641   Output Parameter:
5642 
5643   Level: beginner
5644 
5645 .keywords: mesh
5646 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5647 @*/
5648 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5649 {
5650   DMLabel        label;
5651   PetscErrorCode ierr;
5652 
5653   PetscFunctionBegin;
5654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5655   PetscValidCharPointer(name, 2);
5656   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5657   if (!label) PetscFunctionReturn(0);
5658   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5659   PetscFunctionReturn(0);
5660 }
5661 
5662 /*@
5663   DMGetNumLabels - Return the number of labels defined by the mesh
5664 
5665   Not Collective
5666 
5667   Input Parameter:
5668 . dm   - The DM object
5669 
5670   Output Parameter:
5671 . numLabels - the number of Labels
5672 
5673   Level: intermediate
5674 
5675 .keywords: mesh
5676 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5677 @*/
5678 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5679 {
5680   DMLabelLink next = dm->labels->next;
5681   PetscInt  n    = 0;
5682 
5683   PetscFunctionBegin;
5684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5685   PetscValidPointer(numLabels, 2);
5686   while (next) {++n; next = next->next;}
5687   *numLabels = n;
5688   PetscFunctionReturn(0);
5689 }
5690 
5691 /*@C
5692   DMGetLabelName - Return the name of nth label
5693 
5694   Not Collective
5695 
5696   Input Parameters:
5697 + dm - The DM object
5698 - n  - the label number
5699 
5700   Output Parameter:
5701 . name - the label name
5702 
5703   Level: intermediate
5704 
5705 .keywords: mesh
5706 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5707 @*/
5708 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5709 {
5710   DMLabelLink next = dm->labels->next;
5711   PetscInt  l    = 0;
5712 
5713   PetscFunctionBegin;
5714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5715   PetscValidPointer(name, 3);
5716   while (next) {
5717     if (l == n) {
5718       *name = next->label->name;
5719       PetscFunctionReturn(0);
5720     }
5721     ++l;
5722     next = next->next;
5723   }
5724   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5725 }
5726 
5727 /*@C
5728   DMHasLabel - Determine whether the mesh has a label of a given name
5729 
5730   Not Collective
5731 
5732   Input Parameters:
5733 + dm   - The DM object
5734 - name - The label name
5735 
5736   Output Parameter:
5737 . hasLabel - PETSC_TRUE if the label is present
5738 
5739   Level: intermediate
5740 
5741 .keywords: mesh
5742 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5743 @*/
5744 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5745 {
5746   DMLabelLink    next = dm->labels->next;
5747   PetscErrorCode ierr;
5748 
5749   PetscFunctionBegin;
5750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5751   PetscValidCharPointer(name, 2);
5752   PetscValidPointer(hasLabel, 3);
5753   *hasLabel = PETSC_FALSE;
5754   while (next) {
5755     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5756     if (*hasLabel) break;
5757     next = next->next;
5758   }
5759   PetscFunctionReturn(0);
5760 }
5761 
5762 /*@C
5763   DMGetLabel - Return the label of a given name, or NULL
5764 
5765   Not Collective
5766 
5767   Input Parameters:
5768 + dm   - The DM object
5769 - name - The label name
5770 
5771   Output Parameter:
5772 . label - The DMLabel, or NULL if the label is absent
5773 
5774   Level: intermediate
5775 
5776 .keywords: mesh
5777 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5778 @*/
5779 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5780 {
5781   DMLabelLink    next = dm->labels->next;
5782   PetscBool      hasLabel;
5783   PetscErrorCode ierr;
5784 
5785   PetscFunctionBegin;
5786   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5787   PetscValidCharPointer(name, 2);
5788   PetscValidPointer(label, 3);
5789   *label = NULL;
5790   while (next) {
5791     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5792     if (hasLabel) {
5793       *label = next->label;
5794       break;
5795     }
5796     next = next->next;
5797   }
5798   PetscFunctionReturn(0);
5799 }
5800 
5801 /*@C
5802   DMGetLabelByNum - Return the nth label
5803 
5804   Not Collective
5805 
5806   Input Parameters:
5807 + dm - The DM object
5808 - n  - the label number
5809 
5810   Output Parameter:
5811 . label - the label
5812 
5813   Level: intermediate
5814 
5815 .keywords: mesh
5816 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5817 @*/
5818 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5819 {
5820   DMLabelLink next = dm->labels->next;
5821   PetscInt    l    = 0;
5822 
5823   PetscFunctionBegin;
5824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5825   PetscValidPointer(label, 3);
5826   while (next) {
5827     if (l == n) {
5828       *label = next->label;
5829       PetscFunctionReturn(0);
5830     }
5831     ++l;
5832     next = next->next;
5833   }
5834   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5835 }
5836 
5837 /*@C
5838   DMAddLabel - Add the label to this mesh
5839 
5840   Not Collective
5841 
5842   Input Parameters:
5843 + dm   - The DM object
5844 - label - The DMLabel
5845 
5846   Level: developer
5847 
5848 .keywords: mesh
5849 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5850 @*/
5851 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5852 {
5853   DMLabelLink    tmpLabel;
5854   PetscBool      hasLabel;
5855   PetscErrorCode ierr;
5856 
5857   PetscFunctionBegin;
5858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5859   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5860   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5861   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5862   tmpLabel->label  = label;
5863   tmpLabel->output = PETSC_TRUE;
5864   tmpLabel->next   = dm->labels->next;
5865   dm->labels->next = tmpLabel;
5866   PetscFunctionReturn(0);
5867 }
5868 
5869 /*@C
5870   DMRemoveLabel - Remove the label from this mesh
5871 
5872   Not Collective
5873 
5874   Input Parameters:
5875 + dm   - The DM object
5876 - name - The label name
5877 
5878   Output Parameter:
5879 . label - The DMLabel, or NULL if the label is absent
5880 
5881   Level: developer
5882 
5883 .keywords: mesh
5884 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5885 @*/
5886 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5887 {
5888   DMLabelLink    next = dm->labels->next;
5889   DMLabelLink    last = NULL;
5890   PetscBool      hasLabel;
5891   PetscErrorCode ierr;
5892 
5893   PetscFunctionBegin;
5894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5895   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5896   *label = NULL;
5897   if (!hasLabel) PetscFunctionReturn(0);
5898   while (next) {
5899     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5900     if (hasLabel) {
5901       if (last) last->next       = next->next;
5902       else      dm->labels->next = next->next;
5903       next->next = NULL;
5904       *label     = next->label;
5905       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5906       if (hasLabel) {
5907         dm->depthLabel = NULL;
5908       }
5909       ierr = PetscFree(next);CHKERRQ(ierr);
5910       break;
5911     }
5912     last = next;
5913     next = next->next;
5914   }
5915   PetscFunctionReturn(0);
5916 }
5917 
5918 /*@C
5919   DMGetLabelOutput - Get the output flag for a given label
5920 
5921   Not Collective
5922 
5923   Input Parameters:
5924 + dm   - The DM object
5925 - name - The label name
5926 
5927   Output Parameter:
5928 . output - The flag for output
5929 
5930   Level: developer
5931 
5932 .keywords: mesh
5933 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5934 @*/
5935 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5936 {
5937   DMLabelLink    next = dm->labels->next;
5938   PetscErrorCode ierr;
5939 
5940   PetscFunctionBegin;
5941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5942   PetscValidPointer(name, 2);
5943   PetscValidPointer(output, 3);
5944   while (next) {
5945     PetscBool flg;
5946 
5947     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5948     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5949     next = next->next;
5950   }
5951   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5952 }
5953 
5954 /*@C
5955   DMSetLabelOutput - Set the output flag for a given label
5956 
5957   Not Collective
5958 
5959   Input Parameters:
5960 + dm     - The DM object
5961 . name   - The label name
5962 - output - The flag for output
5963 
5964   Level: developer
5965 
5966 .keywords: mesh
5967 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5968 @*/
5969 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5970 {
5971   DMLabelLink    next = dm->labels->next;
5972   PetscErrorCode ierr;
5973 
5974   PetscFunctionBegin;
5975   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5976   PetscValidPointer(name, 2);
5977   while (next) {
5978     PetscBool flg;
5979 
5980     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5981     if (flg) {next->output = output; PetscFunctionReturn(0);}
5982     next = next->next;
5983   }
5984   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5985 }
5986 
5987 
5988 /*@
5989   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5990 
5991   Collective on DM
5992 
5993   Input Parameter:
5994 . dmA - The DM object with initial labels
5995 
5996   Output Parameter:
5997 . dmB - The DM object with copied labels
5998 
5999   Level: intermediate
6000 
6001   Note: This is typically used when interpolating or otherwise adding to a mesh
6002 
6003 .keywords: mesh
6004 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
6005 @*/
6006 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
6007 {
6008   PetscInt       numLabels, l;
6009   PetscErrorCode ierr;
6010 
6011   PetscFunctionBegin;
6012   if (dmA == dmB) PetscFunctionReturn(0);
6013   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
6014   for (l = 0; l < numLabels; ++l) {
6015     DMLabel     label, labelNew;
6016     const char *name;
6017     PetscBool   flg;
6018 
6019     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
6020     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
6021     if (flg) continue;
6022     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
6023     if (flg) continue;
6024     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
6025     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
6026     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
6027   }
6028   PetscFunctionReturn(0);
6029 }
6030 
6031 /*@
6032   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
6033 
6034   Input Parameter:
6035 . dm - The DM object
6036 
6037   Output Parameter:
6038 . cdm - The coarse DM
6039 
6040   Level: intermediate
6041 
6042 .seealso: DMSetCoarseDM()
6043 @*/
6044 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
6045 {
6046   PetscFunctionBegin;
6047   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6048   PetscValidPointer(cdm, 2);
6049   *cdm = dm->coarseMesh;
6050   PetscFunctionReturn(0);
6051 }
6052 
6053 /*@
6054   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
6055 
6056   Input Parameters:
6057 + dm - The DM object
6058 - cdm - The coarse DM
6059 
6060   Level: intermediate
6061 
6062 .seealso: DMGetCoarseDM()
6063 @*/
6064 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
6065 {
6066   PetscErrorCode ierr;
6067 
6068   PetscFunctionBegin;
6069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6070   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
6071   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6072   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
6073   dm->coarseMesh = cdm;
6074   PetscFunctionReturn(0);
6075 }
6076 
6077 /*@
6078   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
6079 
6080   Input Parameter:
6081 . dm - The DM object
6082 
6083   Output Parameter:
6084 . fdm - The fine DM
6085 
6086   Level: intermediate
6087 
6088 .seealso: DMSetFineDM()
6089 @*/
6090 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
6091 {
6092   PetscFunctionBegin;
6093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6094   PetscValidPointer(fdm, 2);
6095   *fdm = dm->fineMesh;
6096   PetscFunctionReturn(0);
6097 }
6098 
6099 /*@
6100   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
6101 
6102   Input Parameters:
6103 + dm - The DM object
6104 - fdm - The fine DM
6105 
6106   Level: intermediate
6107 
6108 .seealso: DMGetFineDM()
6109 @*/
6110 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
6111 {
6112   PetscErrorCode ierr;
6113 
6114   PetscFunctionBegin;
6115   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6116   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
6117   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
6118   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
6119   dm->fineMesh = fdm;
6120   PetscFunctionReturn(0);
6121 }
6122 
6123 /*=== DMBoundary code ===*/
6124 
6125 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
6126 {
6127   PetscErrorCode ierr;
6128 
6129   PetscFunctionBegin;
6130   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
6131   PetscFunctionReturn(0);
6132 }
6133 
6134 /*@C
6135   DMAddBoundary - Add a boundary condition to the model
6136 
6137   Input Parameters:
6138 + dm          - The DM, with a PetscDS that matches the problem being constrained
6139 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6140 . name        - The BC name
6141 . labelname   - The label defining constrained points
6142 . field       - The field to constrain
6143 . numcomps    - The number of constrained field components
6144 . comps       - An array of constrained component numbers
6145 . bcFunc      - A pointwise function giving boundary values
6146 . numids      - The number of DMLabel ids for constrained points
6147 . ids         - An array of ids for constrained points
6148 - ctx         - An optional user context for bcFunc
6149 
6150   Options Database Keys:
6151 + -bc_<boundary name> <num> - Overrides the boundary ids
6152 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6153 
6154   Level: developer
6155 
6156 .seealso: DMGetBoundary()
6157 @*/
6158 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)
6159 {
6160   PetscErrorCode ierr;
6161 
6162   PetscFunctionBegin;
6163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6164   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
6165   PetscFunctionReturn(0);
6166 }
6167 
6168 /*@
6169   DMGetNumBoundary - Get the number of registered BC
6170 
6171   Input Parameters:
6172 . dm - The mesh object
6173 
6174   Output Parameters:
6175 . numBd - The number of BC
6176 
6177   Level: intermediate
6178 
6179 .seealso: DMAddBoundary(), DMGetBoundary()
6180 @*/
6181 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
6182 {
6183   PetscErrorCode ierr;
6184 
6185   PetscFunctionBegin;
6186   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6187   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
6188   PetscFunctionReturn(0);
6189 }
6190 
6191 /*@C
6192   DMGetBoundary - Get a model boundary condition
6193 
6194   Input Parameters:
6195 + dm          - The mesh object
6196 - bd          - The BC number
6197 
6198   Output Parameters:
6199 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6200 . name        - The BC name
6201 . labelname   - The label defining constrained points
6202 . field       - The field to constrain
6203 . numcomps    - The number of constrained field components
6204 . comps       - An array of constrained component numbers
6205 . bcFunc      - A pointwise function giving boundary values
6206 . numids      - The number of DMLabel ids for constrained points
6207 . ids         - An array of ids for constrained points
6208 - ctx         - An optional user context for bcFunc
6209 
6210   Options Database Keys:
6211 + -bc_<boundary name> <num> - Overrides the boundary ids
6212 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6213 
6214   Level: developer
6215 
6216 .seealso: DMAddBoundary()
6217 @*/
6218 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)
6219 {
6220   PetscErrorCode ierr;
6221 
6222   PetscFunctionBegin;
6223   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6224   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
6225   PetscFunctionReturn(0);
6226 }
6227 
6228 static PetscErrorCode DMPopulateBoundary(DM dm)
6229 {
6230   DMBoundary *lastnext;
6231   DSBoundary dsbound;
6232   PetscErrorCode ierr;
6233 
6234   PetscFunctionBegin;
6235   dsbound = dm->prob->boundary;
6236   if (dm->boundary) {
6237     DMBoundary next = dm->boundary;
6238 
6239     /* quick check to see if the PetscDS has changed */
6240     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
6241     /* the PetscDS has changed: tear down and rebuild */
6242     while (next) {
6243       DMBoundary b = next;
6244 
6245       next = b->next;
6246       ierr = PetscFree(b);CHKERRQ(ierr);
6247     }
6248     dm->boundary = NULL;
6249   }
6250 
6251   lastnext = &(dm->boundary);
6252   while (dsbound) {
6253     DMBoundary dmbound;
6254 
6255     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
6256     dmbound->dsboundary = dsbound;
6257     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
6258     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
6259     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6260     *lastnext = dmbound;
6261     lastnext = &(dmbound->next);
6262     dsbound = dsbound->next;
6263   }
6264   PetscFunctionReturn(0);
6265 }
6266 
6267 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6268 {
6269   DMBoundary     b;
6270   PetscErrorCode ierr;
6271 
6272   PetscFunctionBegin;
6273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6274   PetscValidPointer(isBd, 3);
6275   *isBd = PETSC_FALSE;
6276   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
6277   b = dm->boundary;
6278   while (b && !(*isBd)) {
6279     DMLabel    label = b->label;
6280     DSBoundary dsb = b->dsboundary;
6281 
6282     if (label) {
6283       PetscInt i;
6284 
6285       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6286         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
6287       }
6288     }
6289     b = b->next;
6290   }
6291   PetscFunctionReturn(0);
6292 }
6293 
6294 /*@C
6295   DMProjectFunction - This projects the given function into the function space provided.
6296 
6297   Input Parameters:
6298 + dm      - The DM
6299 . time    - The time
6300 . funcs   - The coordinate functions to evaluate, one per field
6301 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6302 - mode    - The insertion mode for values
6303 
6304   Output Parameter:
6305 . X - vector
6306 
6307    Calling sequence of func:
6308 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
6309 
6310 +  dim - The spatial dimension
6311 .  x   - The coordinates
6312 .  Nf  - The number of fields
6313 .  u   - The output field values
6314 -  ctx - optional user-defined function context
6315 
6316   Level: developer
6317 
6318 .seealso: DMComputeL2Diff()
6319 @*/
6320 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6321 {
6322   Vec            localX;
6323   PetscErrorCode ierr;
6324 
6325   PetscFunctionBegin;
6326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6327   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6328   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6329   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6330   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6331   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6332   PetscFunctionReturn(0);
6333 }
6334 
6335 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6336 {
6337   PetscErrorCode ierr;
6338 
6339   PetscFunctionBegin;
6340   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6341   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6342   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6343   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6344   PetscFunctionReturn(0);
6345 }
6346 
6347 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)
6348 {
6349   Vec            localX;
6350   PetscErrorCode ierr;
6351 
6352   PetscFunctionBegin;
6353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6354   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6355   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6356   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6357   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6358   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6359   PetscFunctionReturn(0);
6360 }
6361 
6362 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)
6363 {
6364   PetscErrorCode ierr;
6365 
6366   PetscFunctionBegin;
6367   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6368   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6369   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6370   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6371   PetscFunctionReturn(0);
6372 }
6373 
6374 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6375                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6376                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6377                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6378                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6379                                    InsertMode mode, Vec localX)
6380 {
6381   PetscErrorCode ierr;
6382 
6383   PetscFunctionBegin;
6384   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6385   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
6386   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
6387   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6388   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
6389   PetscFunctionReturn(0);
6390 }
6391 
6392 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6393                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6394                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6395                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6396                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6397                                         InsertMode mode, Vec localX)
6398 {
6399   PetscErrorCode ierr;
6400 
6401   PetscFunctionBegin;
6402   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6403   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
6404   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
6405   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6406   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
6407   PetscFunctionReturn(0);
6408 }
6409 
6410 /*@C
6411   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
6412 
6413   Input Parameters:
6414 + dm    - The DM
6415 . time  - The time
6416 . funcs - The functions to evaluate for each field component
6417 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6418 - X     - The coefficient vector u_h, a global vector
6419 
6420   Output Parameter:
6421 . diff - The diff ||u - u_h||_2
6422 
6423   Level: developer
6424 
6425 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6426 @*/
6427 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6428 {
6429   PetscErrorCode ierr;
6430 
6431   PetscFunctionBegin;
6432   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6433   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6434   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6435   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6436   PetscFunctionReturn(0);
6437 }
6438 
6439 /*@C
6440   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
6441 
6442   Input Parameters:
6443 + dm    - The DM
6444 , time  - The time
6445 . funcs - The gradient functions to evaluate for each field component
6446 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6447 . X     - The coefficient vector u_h, a global vector
6448 - n     - The vector to project along
6449 
6450   Output Parameter:
6451 . diff - The diff ||(grad u - grad u_h) . n||_2
6452 
6453   Level: developer
6454 
6455 .seealso: DMProjectFunction(), DMComputeL2Diff()
6456 @*/
6457 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)
6458 {
6459   PetscErrorCode ierr;
6460 
6461   PetscFunctionBegin;
6462   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6463   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6464   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6465   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6466   PetscFunctionReturn(0);
6467 }
6468 
6469 /*@C
6470   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6471 
6472   Input Parameters:
6473 + dm    - The DM
6474 . time  - The time
6475 . funcs - The functions to evaluate for each field component
6476 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6477 - X     - The coefficient vector u_h, a global vector
6478 
6479   Output Parameter:
6480 . diff - The array of differences, ||u^f - u^f_h||_2
6481 
6482   Level: developer
6483 
6484 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6485 @*/
6486 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6487 {
6488   PetscErrorCode ierr;
6489 
6490   PetscFunctionBegin;
6491   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6492   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6493   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6494   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6495   PetscFunctionReturn(0);
6496 }
6497 
6498 /*@C
6499   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6500                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6501 
6502   Collective on dm
6503 
6504   Input parameters:
6505 + dm - the pre-adaptation DM object
6506 - label - label with the flags
6507 
6508   Output parameters:
6509 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
6510 
6511   Level: intermediate
6512 
6513 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6514 @*/
6515 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6516 {
6517   PetscErrorCode ierr;
6518 
6519   PetscFunctionBegin;
6520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6521   PetscValidPointer(label,2);
6522   PetscValidPointer(dmAdapt,3);
6523   *dmAdapt = NULL;
6524   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6525   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
6526   PetscFunctionReturn(0);
6527 }
6528 
6529 /*@C
6530   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
6531 
6532   Input Parameters:
6533 + dm - The DM object
6534 . metric - The metric to which the mesh is adapted, defined vertex-wise.
6535 - 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_".
6536 
6537   Output Parameter:
6538 . dmAdapt  - Pointer to the DM object containing the adapted mesh
6539 
6540   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
6541 
6542   Level: advanced
6543 
6544 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6545 @*/
6546 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6547 {
6548   PetscErrorCode ierr;
6549 
6550   PetscFunctionBegin;
6551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6552   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
6553   if (bdLabel) PetscValidPointer(bdLabel, 3);
6554   PetscValidPointer(dmAdapt, 4);
6555   *dmAdapt = NULL;
6556   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6557   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
6558   PetscFunctionReturn(0);
6559 }
6560 
6561 /*@C
6562  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6563 
6564  Not Collective
6565 
6566  Input Parameter:
6567  . dm    - The DM
6568 
6569  Output Parameter:
6570  . nranks - the number of neighbours
6571  . ranks - the neighbors ranks
6572 
6573  Notes:
6574  Do not free the array, it is freed when the DM is destroyed.
6575 
6576  Level: beginner
6577 
6578  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6579 @*/
6580 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6581 {
6582   PetscErrorCode ierr;
6583 
6584   PetscFunctionBegin;
6585   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6586   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6587   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6588   PetscFunctionReturn(0);
6589 }
6590 
6591 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6592 
6593 /*
6594     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6595     This has be a different function because it requires DM which is not defined in the Mat library
6596 */
6597 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6598 {
6599   PetscErrorCode ierr;
6600 
6601   PetscFunctionBegin;
6602   if (coloring->ctype == IS_COLORING_LOCAL) {
6603     Vec x1local;
6604     DM  dm;
6605     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6606     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6607     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6608     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6609     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6610     x1   = x1local;
6611   }
6612   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6613   if (coloring->ctype == IS_COLORING_LOCAL) {
6614     DM  dm;
6615     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6616     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6617   }
6618   PetscFunctionReturn(0);
6619 }
6620 
6621 /*@
6622     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6623 
6624     Input Parameter:
6625 .    coloring - the MatFDColoring object
6626 
6627     Developer Notes:
6628     this routine exists because the PETSc Mat library does not know about the DM objects
6629 
6630     Level: advanced
6631 
6632 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6633 @*/
6634 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6635 {
6636   PetscFunctionBegin;
6637   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6638   PetscFunctionReturn(0);
6639 }
6640 
6641 /*@
6642     DMGetCompatibility - determine if two DMs are compatible
6643 
6644     Collective
6645 
6646     Input Parameters:
6647 +    dm - the first DM
6648 -    dm2 - the second DM
6649 
6650     Output Parameters:
6651 +    compatible - whether or not the two DMs are compatible
6652 -    set - whether or not the compatible value was set
6653 
6654     Notes:
6655     Two DMs are deemed compatible if they represent the same parallel decomposition
6656     of the same topology. This implies that the the section (field data) on one
6657     "makes sense" with respect to the topology and parallel decomposition of the other.
6658     Loosely speaking, compatibile DMs represent the same domain, with the same parallel
6659     decomposition, with different data.
6660 
6661     Typically, one would confirm compatibility if intending to simultaneously iterate
6662     over a pair of vectors obtained from different DMs.
6663 
6664     For example, two DMDA objects are compatible if they have the same local
6665     and global sizes and the same stencil width. They can have different numbers
6666     of degrees of freedom per node. Thus, one could use the node numbering from
6667     either DM in bounds for a loop over vectors derived from either DM.
6668 
6669     Consider the operation of summing data living on a 2-dof DMDA to data living
6670     on a 1-dof DMDA, which should be compatible, as in the following snippet.
6671 .vb
6672   ...
6673   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
6674   if (set && compatible)  {
6675     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6676     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6677     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n);CHKERRQ(ierr);
6678     for (j=y; j<y+n; ++j) {
6679       for (i=x; i<x+m, ++i) {
6680         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
6681       }
6682     }
6683     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6684     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6685   } else {
6686     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
6687   }
6688   ...
6689 .ve
6690 
6691     Checking compatibility might be expensive for a given implementation of DM,
6692     or might be impossible to unambiguously confirm or deny. For this reason,
6693     this function may decline to determine compatibility, and hence users should
6694     always check the "set" output parameter.
6695 
6696     A DM is always compatible with itself.
6697 
6698     In the current implementation, DMs which live on "unequal" communicators
6699     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
6700     incompatible.
6701 
6702     This function is labeled "Collective," as information about all subdomains
6703     is required on each rank. However, in DM implementations which store all this
6704     information locally, this function may be merely "Logically Collective".
6705 
6706     Developer Notes:
6707     Compatibility is assumed to be a symmetric concept; if DM A is compatible with DM B,
6708     the DM B is compatible with DM A. Thus, this function checks the implementations
6709     of both dm and dm2 (if they are of different types), attempting to determine
6710     compatibility. It is left to DM implementers to ensure that symmetry is
6711     preserved. The simplest way to do this is, when implementing type-specific
6712     logic for this function, to check for existing logic in the implementation
6713     of other DM types and let *set = PETSC_FALSE if found; the logic of this
6714     function will then call that logic.
6715 
6716     Level: advanced
6717 
6718 .seealso: DM, DMDACreateCompatibleDMDA()
6719 @*/
6720 
6721 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
6722 {
6723   PetscErrorCode ierr;
6724   PetscMPIInt    compareResult;
6725   DMType         type,type2;
6726   PetscBool      sameType;
6727 
6728   PetscFunctionBegin;
6729   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6730   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
6731 
6732   /* Declare a DM compatible with itself */
6733   if (dm == dm2) {
6734     *set = PETSC_TRUE;
6735     *compatible = PETSC_TRUE;
6736     PetscFunctionReturn(0);
6737   }
6738 
6739   /* Declare a DM incompatible with a DM that lives on an "unequal"
6740      communicator. Note that this does not preclude compatibility with
6741      DMs living on "congruent" or "similar" communicators, but this must be
6742      determined by the implementation-specific logic */
6743   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
6744   if (compareResult == MPI_UNEQUAL) {
6745     *set = PETSC_TRUE;
6746     *compatible = PETSC_FALSE;
6747     PetscFunctionReturn(0);
6748   }
6749 
6750   /* Pass to the implementation-specific routine, if one exists. */
6751   if (dm->ops->getcompatibility) {
6752     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
6753     if (*set) {
6754       PetscFunctionReturn(0);
6755     }
6756   }
6757 
6758   /* If dm and dm2 are of different types, then attempt to check compatibility
6759      with an implementation of this function from dm2 */
6760   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
6761   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
6762   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
6763   if (!sameType && dm2->ops->getcompatibility) {
6764     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
6765   } else {
6766     *set = PETSC_FALSE;
6767   }
6768   PetscFunctionReturn(0);
6769 }
6770