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