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