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