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