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