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