xref: /petsc/src/dm/interface/dm.c (revision 9435951e5d58a9a8b01c7ece939244d29b452105)
1 #include <petsc-private/dmimpl.h>     /*I      "petscdm.h"     I*/
2 #include <petscsf.h>
3 #include <petscds.h>
4 
5 PetscClassId  DM_CLASSID;
6 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal;
7 
8 const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DM_BOUNDARY_",0};
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "DMCreate"
12 /*@
13   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
14 
15    If you never  call DMSetType()  it will generate an
16    error when you try to use the vector.
17 
18   Collective on MPI_Comm
19 
20   Input Parameter:
21 . comm - The communicator for the DM object
22 
23   Output Parameter:
24 . dm - The DM object
25 
26   Level: beginner
27 
28 .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE
29 @*/
30 PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
31 {
32   DM             v;
33   PetscErrorCode ierr;
34 
35   PetscFunctionBegin;
36   PetscValidPointer(dm,2);
37   *dm = NULL;
38   ierr = PetscSysInitializePackage();CHKERRQ(ierr);
39   ierr = VecInitializePackage();CHKERRQ(ierr);
40   ierr = MatInitializePackage();CHKERRQ(ierr);
41   ierr = DMInitializePackage();CHKERRQ(ierr);
42 
43   ierr = PetscHeaderCreate(v, _p_DM, struct _DMOps, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);CHKERRQ(ierr);
44   ierr = PetscMemzero(v->ops, sizeof(struct _DMOps));CHKERRQ(ierr);
45 
46 
47   v->ltogmap              = NULL;
48   v->bs                   = 1;
49   v->coloringtype         = IS_COLORING_GLOBAL;
50   ierr                    = PetscSFCreate(comm, &v->sf);CHKERRQ(ierr);
51   ierr                    = PetscSFCreate(comm, &v->defaultSF);CHKERRQ(ierr);
52   v->defaultSection       = NULL;
53   v->defaultGlobalSection = NULL;
54   v->L                    = NULL;
55   v->maxCell              = NULL;
56   v->dimEmbed             = PETSC_DEFAULT;
57   {
58     PetscInt i;
59     for (i = 0; i < 10; ++i) {
60       v->nullspaceConstructors[i] = NULL;
61     }
62   }
63   ierr = PetscDSCreate(comm, &v->prob);CHKERRQ(ierr);
64   v->dmBC = NULL;
65   v->outputSequenceNum = -1;
66   v->outputSequenceVal = 0.0;
67   ierr = DMSetVecType(v,VECSTANDARD);CHKERRQ(ierr);
68   ierr = DMSetMatType(v,MATAIJ);CHKERRQ(ierr);
69   *dm = v;
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "DMClone"
75 /*@
76   DMClone - Creates a DM object with the same topology as the original.
77 
78   Collective on MPI_Comm
79 
80   Input Parameter:
81 . dm - The original DM object
82 
83   Output Parameter:
84 . newdm  - The new DM object
85 
86   Level: beginner
87 
88 .keywords: DM, topology, create
89 @*/
90 PetscErrorCode DMClone(DM dm, DM *newdm)
91 {
92   PetscSF        sf;
93   Vec            coords;
94   void          *ctx;
95   PetscInt       dim;
96   PetscErrorCode ierr;
97 
98   PetscFunctionBegin;
99   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100   PetscValidPointer(newdm,2);
101   ierr = DMCreate(PetscObjectComm((PetscObject)dm), newdm);CHKERRQ(ierr);
102   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
103   ierr = DMSetDimension(*newdm, dim);CHKERRQ(ierr);
104   if (dm->ops->clone) {
105     ierr = (*dm->ops->clone)(dm, newdm);CHKERRQ(ierr);
106   }
107   (*newdm)->setupcalled = PETSC_TRUE;
108   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
109   ierr = DMSetPointSF(*newdm, sf);CHKERRQ(ierr);
110   ierr = DMGetApplicationContext(dm, &ctx);CHKERRQ(ierr);
111   ierr = DMSetApplicationContext(*newdm, ctx);CHKERRQ(ierr);
112   ierr = DMGetCoordinatesLocal(dm, &coords);CHKERRQ(ierr);
113   if (coords) {
114     ierr = DMSetCoordinatesLocal(*newdm, coords);CHKERRQ(ierr);
115   } else {
116     ierr = DMGetCoordinates(dm, &coords);CHKERRQ(ierr);
117     if (coords) {ierr = DMSetCoordinates(*newdm, coords);CHKERRQ(ierr);}
118   }
119   if (dm->maxCell) {
120     const PetscReal *maxCell, *L;
121     ierr = DMGetPeriodicity(dm,     &maxCell, &L);CHKERRQ(ierr);
122     ierr = DMSetPeriodicity(*newdm,  maxCell,  L);CHKERRQ(ierr);
123   }
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "DMSetVecType"
129 /*@C
130        DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
131 
132    Logically Collective on DMDA
133 
134    Input Parameter:
135 +  da - initial distributed array
136 .  ctype - the vector type, currently either VECSTANDARD or VECCUSP
137 
138    Options Database:
139 .   -dm_vec_type ctype
140 
141    Level: intermediate
142 
143 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType, VecType, DMGetVecType()
144 @*/
145 PetscErrorCode  DMSetVecType(DM da,VecType ctype)
146 {
147   PetscErrorCode ierr;
148 
149   PetscFunctionBegin;
150   PetscValidHeaderSpecific(da,DM_CLASSID,1);
151   ierr = PetscFree(da->vectype);CHKERRQ(ierr);
152   ierr = PetscStrallocpy(ctype,(char**)&da->vectype);CHKERRQ(ierr);
153   PetscFunctionReturn(0);
154 }
155 
156 #undef __FUNCT__
157 #define __FUNCT__ "DMGetVecType"
158 /*@C
159        DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
160 
161    Logically Collective on DMDA
162 
163    Input Parameter:
164 .  da - initial distributed array
165 
166    Output Parameter:
167 .  ctype - the vector type
168 
169    Level: intermediate
170 
171 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType, VecType
172 @*/
173 PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
174 {
175   PetscFunctionBegin;
176   PetscValidHeaderSpecific(da,DM_CLASSID,1);
177   *ctype = da->vectype;
178   PetscFunctionReturn(0);
179 }
180 
181 #undef __FUNCT__
182 #define __FUNCT__ "VecGetDM"
183 /*@
184   VecGetDM - Gets the DM defining the data layout of the vector
185 
186   Not collective
187 
188   Input Parameter:
189 . v - The Vec
190 
191   Output Parameter:
192 . dm - The DM
193 
194   Level: intermediate
195 
196 .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
197 @*/
198 PetscErrorCode VecGetDM(Vec v, DM *dm)
199 {
200   PetscErrorCode ierr;
201 
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
204   PetscValidPointer(dm,2);
205   ierr = PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
206   PetscFunctionReturn(0);
207 }
208 
209 #undef __FUNCT__
210 #define __FUNCT__ "VecSetDM"
211 /*@
212   VecSetDM - Sets the DM defining the data layout of the vector
213 
214   Not collective
215 
216   Input Parameters:
217 + v - The Vec
218 - dm - The DM
219 
220   Level: intermediate
221 
222 .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
223 @*/
224 PetscErrorCode VecSetDM(Vec v, DM dm)
225 {
226   PetscErrorCode ierr;
227 
228   PetscFunctionBegin;
229   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
230   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
231   ierr = PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
232   PetscFunctionReturn(0);
233 }
234 
235 #undef __FUNCT__
236 #define __FUNCT__ "DMSetMatType"
237 /*@C
238        DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
239 
240    Logically Collective on DM
241 
242    Input Parameter:
243 +  dm - the DM context
244 .  ctype - the matrix type
245 
246    Options Database:
247 .   -dm_mat_type ctype
248 
249    Level: intermediate
250 
251 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
252 @*/
253 PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
254 {
255   PetscErrorCode ierr;
256 
257   PetscFunctionBegin;
258   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
259   ierr = PetscFree(dm->mattype);CHKERRQ(ierr);
260   ierr = PetscStrallocpy(ctype,(char**)&dm->mattype);CHKERRQ(ierr);
261   PetscFunctionReturn(0);
262 }
263 
264 #undef __FUNCT__
265 #define __FUNCT__ "DMGetMatType"
266 /*@C
267        DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
268 
269    Logically Collective on DM
270 
271    Input Parameter:
272 .  dm - the DM context
273 
274    Output Parameter:
275 .  ctype - the matrix type
276 
277    Options Database:
278 .   -dm_mat_type ctype
279 
280    Level: intermediate
281 
282 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType()
283 @*/
284 PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
285 {
286   PetscFunctionBegin;
287   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
288   *ctype = dm->mattype;
289   PetscFunctionReturn(0);
290 }
291 
292 #undef __FUNCT__
293 #define __FUNCT__ "MatGetDM"
294 /*@
295   MatGetDM - Gets the DM defining the data layout of the matrix
296 
297   Not collective
298 
299   Input Parameter:
300 . A - The Mat
301 
302   Output Parameter:
303 . dm - The DM
304 
305   Level: intermediate
306 
307 .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
308 @*/
309 PetscErrorCode MatGetDM(Mat A, DM *dm)
310 {
311   PetscErrorCode ierr;
312 
313   PetscFunctionBegin;
314   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
315   PetscValidPointer(dm,2);
316   ierr = PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 #undef __FUNCT__
321 #define __FUNCT__ "MatSetDM"
322 /*@
323   MatSetDM - Sets the DM defining the data layout of the matrix
324 
325   Not collective
326 
327   Input Parameters:
328 + A - The Mat
329 - dm - The DM
330 
331   Level: intermediate
332 
333 .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
334 @*/
335 PetscErrorCode MatSetDM(Mat A, DM dm)
336 {
337   PetscErrorCode ierr;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
341   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
342   ierr = PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "DMSetOptionsPrefix"
348 /*@C
349    DMSetOptionsPrefix - Sets the prefix used for searching for all
350    DMDA options in the database.
351 
352    Logically Collective on DMDA
353 
354    Input Parameter:
355 +  da - the DMDA context
356 -  prefix - the prefix to prepend to all option names
357 
358    Notes:
359    A hyphen (-) must NOT be given at the beginning of the prefix name.
360    The first character of all runtime options is AUTOMATICALLY the hyphen.
361 
362    Level: advanced
363 
364 .keywords: DMDA, set, options, prefix, database
365 
366 .seealso: DMSetFromOptions()
367 @*/
368 PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
369 {
370   PetscErrorCode ierr;
371 
372   PetscFunctionBegin;
373   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
374   ierr = PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
375   PetscFunctionReturn(0);
376 }
377 
378 #undef __FUNCT__
379 #define __FUNCT__ "DMDestroy"
380 /*@
381     DMDestroy - Destroys a vector packer or DMDA.
382 
383     Collective on DM
384 
385     Input Parameter:
386 .   dm - the DM object to destroy
387 
388     Level: developer
389 
390 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
391 
392 @*/
393 PetscErrorCode  DMDestroy(DM *dm)
394 {
395   PetscInt       i, cnt = 0;
396   DMNamedVecLink nlink,nnext;
397   PetscErrorCode ierr;
398 
399   PetscFunctionBegin;
400   if (!*dm) PetscFunctionReturn(0);
401   PetscValidHeaderSpecific((*dm),DM_CLASSID,1);
402 
403   /* count all the circular references of DM and its contained Vecs */
404   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
405     if ((*dm)->localin[i])  cnt++;
406     if ((*dm)->globalin[i]) cnt++;
407   }
408   for (nlink=(*dm)->namedglobal; nlink; nlink=nlink->next) cnt++;
409   for (nlink=(*dm)->namedlocal; nlink; nlink=nlink->next) cnt++;
410   if ((*dm)->x) {
411     DM obj;
412     ierr = VecGetDM((*dm)->x, &obj);CHKERRQ(ierr);
413     if (obj == *dm) cnt++;
414   }
415 
416   if (--((PetscObject)(*dm))->refct - cnt > 0) {*dm = 0; PetscFunctionReturn(0);}
417   /*
418      Need this test because the dm references the vectors that
419      reference the dm, so destroying the dm calls destroy on the
420      vectors that cause another destroy on the dm
421   */
422   if (((PetscObject)(*dm))->refct < 0) PetscFunctionReturn(0);
423   ((PetscObject) (*dm))->refct = 0;
424   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
425     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
426     ierr = VecDestroy(&(*dm)->localin[i]);CHKERRQ(ierr);
427   }
428   nnext=(*dm)->namedglobal;
429   (*dm)->namedglobal = NULL;
430   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
431     nnext = nlink->next;
432     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
433     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
434     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
435     ierr = PetscFree(nlink);CHKERRQ(ierr);
436   }
437   nnext=(*dm)->namedlocal;
438   (*dm)->namedlocal = NULL;
439   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
440     nnext = nlink->next;
441     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
442     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
443     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
444     ierr = PetscFree(nlink);CHKERRQ(ierr);
445   }
446 
447   /* Destroy the list of hooks */
448   {
449     DMCoarsenHookLink link,next;
450     for (link=(*dm)->coarsenhook; link; link=next) {
451       next = link->next;
452       ierr = PetscFree(link);CHKERRQ(ierr);
453     }
454     (*dm)->coarsenhook = NULL;
455   }
456   {
457     DMRefineHookLink link,next;
458     for (link=(*dm)->refinehook; link; link=next) {
459       next = link->next;
460       ierr = PetscFree(link);CHKERRQ(ierr);
461     }
462     (*dm)->refinehook = NULL;
463   }
464   {
465     DMSubDomainHookLink link,next;
466     for (link=(*dm)->subdomainhook; link; link=next) {
467       next = link->next;
468       ierr = PetscFree(link);CHKERRQ(ierr);
469     }
470     (*dm)->subdomainhook = NULL;
471   }
472   {
473     DMGlobalToLocalHookLink link,next;
474     for (link=(*dm)->gtolhook; link; link=next) {
475       next = link->next;
476       ierr = PetscFree(link);CHKERRQ(ierr);
477     }
478     (*dm)->gtolhook = NULL;
479   }
480   {
481     DMLocalToGlobalHookLink link,next;
482     for (link=(*dm)->ltoghook; link; link=next) {
483       next = link->next;
484       ierr = PetscFree(link);CHKERRQ(ierr);
485     }
486     (*dm)->ltoghook = NULL;
487   }
488   /* Destroy the work arrays */
489   {
490     DMWorkLink link,next;
491     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
492     for (link=(*dm)->workin; link; link=next) {
493       next = link->next;
494       ierr = PetscFree(link->mem);CHKERRQ(ierr);
495       ierr = PetscFree(link);CHKERRQ(ierr);
496     }
497     (*dm)->workin = NULL;
498   }
499 
500   ierr = PetscObjectDestroy(&(*dm)->dmksp);CHKERRQ(ierr);
501   ierr = PetscObjectDestroy(&(*dm)->dmsnes);CHKERRQ(ierr);
502   ierr = PetscObjectDestroy(&(*dm)->dmts);CHKERRQ(ierr);
503 
504   if ((*dm)->ctx && (*dm)->ctxdestroy) {
505     ierr = (*(*dm)->ctxdestroy)(&(*dm)->ctx);CHKERRQ(ierr);
506   }
507   ierr = VecDestroy(&(*dm)->x);CHKERRQ(ierr);
508   ierr = MatFDColoringDestroy(&(*dm)->fd);CHKERRQ(ierr);
509   ierr = DMClearGlobalVectors(*dm);CHKERRQ(ierr);
510   ierr = ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);CHKERRQ(ierr);
511   ierr = PetscFree((*dm)->vectype);CHKERRQ(ierr);
512   ierr = PetscFree((*dm)->mattype);CHKERRQ(ierr);
513 
514   ierr = PetscSectionDestroy(&(*dm)->defaultSection);CHKERRQ(ierr);
515   ierr = PetscSectionDestroy(&(*dm)->defaultGlobalSection);CHKERRQ(ierr);
516   ierr = PetscLayoutDestroy(&(*dm)->map);CHKERRQ(ierr);
517   ierr = PetscSFDestroy(&(*dm)->sf);CHKERRQ(ierr);
518   ierr = PetscSFDestroy(&(*dm)->defaultSF);CHKERRQ(ierr);
519 
520   ierr = DMDestroy(&(*dm)->coordinateDM);CHKERRQ(ierr);
521   ierr = VecDestroy(&(*dm)->coordinates);CHKERRQ(ierr);
522   ierr = VecDestroy(&(*dm)->coordinatesLocal);CHKERRQ(ierr);
523   ierr = PetscFree((*dm)->maxCell);CHKERRQ(ierr);
524   ierr = PetscFree((*dm)->L);CHKERRQ(ierr);
525 
526   ierr = PetscDSDestroy(&(*dm)->prob);CHKERRQ(ierr);
527   ierr = DMDestroy(&(*dm)->dmBC);CHKERRQ(ierr);
528   /* if memory was published with SAWs then destroy it */
529   ierr = PetscObjectSAWsViewOff((PetscObject)*dm);CHKERRQ(ierr);
530 
531   ierr = (*(*dm)->ops->destroy)(*dm);CHKERRQ(ierr);
532   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
533   ierr = PetscHeaderDestroy(dm);CHKERRQ(ierr);
534   PetscFunctionReturn(0);
535 }
536 
537 #undef __FUNCT__
538 #define __FUNCT__ "DMSetUp"
539 /*@
540     DMSetUp - sets up the data structures inside a DM object
541 
542     Collective on DM
543 
544     Input Parameter:
545 .   dm - the DM object to setup
546 
547     Level: developer
548 
549 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
550 
551 @*/
552 PetscErrorCode  DMSetUp(DM dm)
553 {
554   PetscErrorCode ierr;
555 
556   PetscFunctionBegin;
557   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
558   if (dm->setupcalled) PetscFunctionReturn(0);
559   if (dm->ops->setup) {
560     ierr = (*dm->ops->setup)(dm);CHKERRQ(ierr);
561   }
562   dm->setupcalled = PETSC_TRUE;
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "DMSetFromOptions"
568 /*@
569     DMSetFromOptions - sets parameters in a DM from the options database
570 
571     Collective on DM
572 
573     Input Parameter:
574 .   dm - the DM object to set options for
575 
576     Options Database:
577 +   -dm_preallocate_only: Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
578 .   -dm_vec_type <type>  type of vector to create inside DM
579 .   -dm_mat_type <type>  type of matrix to create inside DM
580 -   -dm_coloring_type <global or ghosted>
581 
582     Level: developer
583 
584 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
585 
586 @*/
587 PetscErrorCode  DMSetFromOptions(DM dm)
588 {
589   char           typeName[256];
590   PetscBool      flg;
591   PetscErrorCode ierr;
592 
593   PetscFunctionBegin;
594   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
595   ierr = PetscObjectOptionsBegin((PetscObject)dm);CHKERRQ(ierr);
596   ierr = PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);CHKERRQ(ierr);
597   ierr = PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);CHKERRQ(ierr);
598   if (flg) {
599     ierr = DMSetVecType(dm,typeName);CHKERRQ(ierr);
600   }
601   ierr = PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);CHKERRQ(ierr);
602   if (flg) {
603     ierr = DMSetMatType(dm,typeName);CHKERRQ(ierr);
604   }
605   ierr = PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","ISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);CHKERRQ(ierr);
606   if (dm->ops->setfromoptions) {
607     ierr = (*dm->ops->setfromoptions)(dm);CHKERRQ(ierr);
608   }
609   /* process any options handlers added with PetscObjectAddOptionsHandler() */
610   ierr = PetscObjectProcessOptionsHandlers((PetscObject) dm);CHKERRQ(ierr);
611   ierr = PetscOptionsEnd();CHKERRQ(ierr);
612   PetscFunctionReturn(0);
613 }
614 
615 #undef __FUNCT__
616 #define __FUNCT__ "DMView"
617 /*@C
618     DMView - Views a vector packer or DMDA.
619 
620     Collective on DM
621 
622     Input Parameter:
623 +   dm - the DM object to view
624 -   v - the viewer
625 
626     Level: developer
627 
628 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
629 
630 @*/
631 PetscErrorCode  DMView(DM dm,PetscViewer v)
632 {
633   PetscErrorCode ierr;
634   PetscBool      isbinary;
635 
636   PetscFunctionBegin;
637   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
638   if (!v) {
639     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);CHKERRQ(ierr);
640   }
641   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);CHKERRQ(ierr);
642   ierr = PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
643   if (isbinary) {
644     PetscInt classid = DM_FILE_CLASSID;
645     char     type[256];
646 
647     ierr = PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
648     ierr = PetscStrncpy(type,((PetscObject)dm)->type_name,256);CHKERRQ(ierr);
649     ierr = PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
650   }
651   if (dm->ops->view) {
652     ierr = (*dm->ops->view)(dm,v);CHKERRQ(ierr);
653   }
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "DMCreateGlobalVector"
659 /*@
660     DMCreateGlobalVector - Creates a global vector from a DMDA or DMComposite object
661 
662     Collective on DM
663 
664     Input Parameter:
665 .   dm - the DM object
666 
667     Output Parameter:
668 .   vec - the global vector
669 
670     Level: beginner
671 
672 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
673 
674 @*/
675 PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
676 {
677   PetscErrorCode ierr;
678 
679   PetscFunctionBegin;
680   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
681   ierr = (*dm->ops->createglobalvector)(dm,vec);CHKERRQ(ierr);
682   PetscFunctionReturn(0);
683 }
684 
685 #undef __FUNCT__
686 #define __FUNCT__ "DMCreateLocalVector"
687 /*@
688     DMCreateLocalVector - Creates a local vector from a DMDA or DMComposite object
689 
690     Not Collective
691 
692     Input Parameter:
693 .   dm - the DM object
694 
695     Output Parameter:
696 .   vec - the local vector
697 
698     Level: beginner
699 
700 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
701 
702 @*/
703 PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
704 {
705   PetscErrorCode ierr;
706 
707   PetscFunctionBegin;
708   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
709   ierr = (*dm->ops->createlocalvector)(dm,vec);CHKERRQ(ierr);
710   PetscFunctionReturn(0);
711 }
712 
713 #undef __FUNCT__
714 #define __FUNCT__ "DMGetLocalToGlobalMapping"
715 /*@
716    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
717 
718    Collective on DM
719 
720    Input Parameter:
721 .  dm - the DM that provides the mapping
722 
723    Output Parameter:
724 .  ltog - the mapping
725 
726    Level: intermediate
727 
728    Notes:
729    This mapping can then be used by VecSetLocalToGlobalMapping() or
730    MatSetLocalToGlobalMapping().
731 
732 .seealso: DMCreateLocalVector()
733 @*/
734 PetscErrorCode  DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
735 {
736   PetscErrorCode ierr;
737 
738   PetscFunctionBegin;
739   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
740   PetscValidPointer(ltog,2);
741   if (!dm->ltogmap) {
742     PetscSection section, sectionGlobal;
743 
744     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
745     if (section) {
746       PetscInt *ltog;
747       PetscInt pStart, pEnd, size, p, l;
748 
749       ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
750       ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
751       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
752       ierr = PetscMalloc1(size, &ltog);CHKERRQ(ierr); /* We want the local+overlap size */
753       for (p = pStart, l = 0; p < pEnd; ++p) {
754         PetscInt dof, off, c;
755 
756         /* Should probably use constrained dofs */
757         ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
758         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
759         for (c = 0; c < dof; ++c, ++l) {
760           ltog[l] = off+c;
761         }
762       }
763       ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1,size, ltog, PETSC_OWN_POINTER, &dm->ltogmap);CHKERRQ(ierr);
764       ierr = PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);CHKERRQ(ierr);
765     } else {
766       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
767       ierr = (*dm->ops->getlocaltoglobalmapping)(dm);CHKERRQ(ierr);
768     }
769   }
770   *ltog = dm->ltogmap;
771   PetscFunctionReturn(0);
772 }
773 
774 #undef __FUNCT__
775 #define __FUNCT__ "DMGetBlockSize"
776 /*@
777    DMGetBlockSize - Gets the inherent block size associated with a DM
778 
779    Not Collective
780 
781    Input Parameter:
782 .  dm - the DM with block structure
783 
784    Output Parameter:
785 .  bs - the block size, 1 implies no exploitable block structure
786 
787    Level: intermediate
788 
789 .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
790 @*/
791 PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
792 {
793   PetscFunctionBegin;
794   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
795   PetscValidPointer(bs,2);
796   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
797   *bs = dm->bs;
798   PetscFunctionReturn(0);
799 }
800 
801 #undef __FUNCT__
802 #define __FUNCT__ "DMCreateInterpolation"
803 /*@
804     DMCreateInterpolation - Gets interpolation matrix between two DMDA or DMComposite objects
805 
806     Collective on DM
807 
808     Input Parameter:
809 +   dm1 - the DM object
810 -   dm2 - the second, finer DM object
811 
812     Output Parameter:
813 +  mat - the interpolation
814 -  vec - the scaling (optional)
815 
816     Level: developer
817 
818     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
819         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
820 
821         For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
822         EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
823 
824 
825 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen()
826 
827 @*/
828 PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
829 {
830   PetscErrorCode ierr;
831 
832   PetscFunctionBegin;
833   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
834   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
835   ierr = (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);CHKERRQ(ierr);
836   PetscFunctionReturn(0);
837 }
838 
839 #undef __FUNCT__
840 #define __FUNCT__ "DMCreateInjection"
841 /*@
842     DMCreateInjection - Gets injection matrix between two DMDA or DMComposite objects
843 
844     Collective on DM
845 
846     Input Parameter:
847 +   dm1 - the DM object
848 -   dm2 - the second, finer DM object
849 
850     Output Parameter:
851 .   ctx - the injection
852 
853     Level: developer
854 
855    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
856         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
857 
858 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
859 
860 @*/
861 PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,VecScatter *ctx)
862 {
863   PetscErrorCode ierr;
864 
865   PetscFunctionBegin;
866   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
867   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
868   ierr = (*dm1->ops->getinjection)(dm1,dm2,ctx);CHKERRQ(ierr);
869   PetscFunctionReturn(0);
870 }
871 
872 #undef __FUNCT__
873 #define __FUNCT__ "DMCreateColoring"
874 /*@
875     DMCreateColoring - Gets coloring for a DM
876 
877     Collective on DM
878 
879     Input Parameter:
880 +   dm - the DM object
881 -   ctype - IS_COLORING_GHOSTED or IS_COLORING_GLOBAL
882 
883     Output Parameter:
884 .   coloring - the coloring
885 
886     Level: developer
887 
888 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType()
889 
890 @*/
891 PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
892 {
893   PetscErrorCode ierr;
894 
895   PetscFunctionBegin;
896   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
897   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
898   ierr = (*dm->ops->getcoloring)(dm,ctype,coloring);CHKERRQ(ierr);
899   PetscFunctionReturn(0);
900 }
901 
902 #undef __FUNCT__
903 #define __FUNCT__ "DMCreateMatrix"
904 /*@
905     DMCreateMatrix - Gets empty Jacobian for a DMDA or DMComposite
906 
907     Collective on DM
908 
909     Input Parameter:
910 .   dm - the DM object
911 
912     Output Parameter:
913 .   mat - the empty Jacobian
914 
915     Level: beginner
916 
917     Notes: This properly preallocates the number of nonzeros in the sparse matrix so you
918        do not need to do it yourself.
919 
920        By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
921        the nonzero pattern call DMDASetMatPreallocateOnly()
922 
923        For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
924        internally by PETSc.
925 
926        For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
927        the indices for the global numbering for DMDAs which is complicated.
928 
929 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
930 
931 @*/
932 PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
933 {
934   PetscErrorCode ierr;
935 
936   PetscFunctionBegin;
937   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
938   ierr = MatInitializePackage();CHKERRQ(ierr);
939   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
940   PetscValidPointer(mat,3);
941   ierr = (*dm->ops->creatematrix)(dm,mat);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMSetMatrixPreallocateOnly"
947 /*@
948   DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
949     preallocated but the nonzero structure and zero values will not be set.
950 
951   Logically Collective on DMDA
952 
953   Input Parameter:
954 + dm - the DM
955 - only - PETSC_TRUE if only want preallocation
956 
957   Level: developer
958 .seealso DMCreateMatrix()
959 @*/
960 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
961 {
962   PetscFunctionBegin;
963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
964   dm->prealloc_only = only;
965   PetscFunctionReturn(0);
966 }
967 
968 #undef __FUNCT__
969 #define __FUNCT__ "DMGetWorkArray"
970 /*@C
971   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
972 
973   Not Collective
974 
975   Input Parameters:
976 + dm - the DM object
977 . count - The minium size
978 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
979 
980   Output Parameter:
981 . array - the work array
982 
983   Level: developer
984 
985 .seealso DMDestroy(), DMCreate()
986 @*/
987 PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
988 {
989   PetscErrorCode ierr;
990   DMWorkLink     link;
991   size_t         size;
992 
993   PetscFunctionBegin;
994   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
995   PetscValidPointer(mem,4);
996   if (dm->workin) {
997     link       = dm->workin;
998     dm->workin = dm->workin->next;
999   } else {
1000     ierr = PetscNewLog(dm,&link);CHKERRQ(ierr);
1001   }
1002   ierr = PetscDataTypeGetSize(dtype,&size);CHKERRQ(ierr);
1003   if (size*count > link->bytes) {
1004     ierr        = PetscFree(link->mem);CHKERRQ(ierr);
1005     ierr        = PetscMalloc(size*count,&link->mem);CHKERRQ(ierr);
1006     link->bytes = size*count;
1007   }
1008   link->next   = dm->workout;
1009   dm->workout  = link;
1010   *(void**)mem = link->mem;
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMRestoreWorkArray"
1016 /*@C
1017   DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1018 
1019   Not Collective
1020 
1021   Input Parameters:
1022 + dm - the DM object
1023 . count - The minium size
1024 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
1025 
1026   Output Parameter:
1027 . array - the work array
1028 
1029   Level: developer
1030 
1031 .seealso DMDestroy(), DMCreate()
1032 @*/
1033 PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1034 {
1035   DMWorkLink *p,link;
1036 
1037   PetscFunctionBegin;
1038   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1039   PetscValidPointer(mem,4);
1040   for (p=&dm->workout; (link=*p); p=&link->next) {
1041     if (link->mem == *(void**)mem) {
1042       *p           = link->next;
1043       link->next   = dm->workin;
1044       dm->workin   = link;
1045       *(void**)mem = NULL;
1046       PetscFunctionReturn(0);
1047     }
1048   }
1049   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "DMSetNullSpaceConstructor"
1055 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1056 {
1057   PetscFunctionBegin;
1058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1059   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1060   dm->nullspaceConstructors[field] = nullsp;
1061   PetscFunctionReturn(0);
1062 }
1063 
1064 #undef __FUNCT__
1065 #define __FUNCT__ "DMCreateFieldIS"
1066 /*@C
1067   DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1068 
1069   Not collective
1070 
1071   Input Parameter:
1072 . dm - the DM object
1073 
1074   Output Parameters:
1075 + numFields  - The number of fields (or NULL if not requested)
1076 . fieldNames - The name for each field (or NULL if not requested)
1077 - fields     - The global indices for each field (or NULL if not requested)
1078 
1079   Level: intermediate
1080 
1081   Notes:
1082   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1083   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1084   PetscFree().
1085 
1086 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1087 @*/
1088 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1089 {
1090   PetscSection   section, sectionGlobal;
1091   PetscErrorCode ierr;
1092 
1093   PetscFunctionBegin;
1094   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1095   if (numFields) {
1096     PetscValidPointer(numFields,2);
1097     *numFields = 0;
1098   }
1099   if (fieldNames) {
1100     PetscValidPointer(fieldNames,3);
1101     *fieldNames = NULL;
1102   }
1103   if (fields) {
1104     PetscValidPointer(fields,4);
1105     *fields = NULL;
1106   }
1107   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1108   if (section) {
1109     PetscInt *fieldSizes, **fieldIndices;
1110     PetscInt nF, f, pStart, pEnd, p;
1111 
1112     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1113     ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1114     ierr = PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);CHKERRQ(ierr);
1115     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1116     for (f = 0; f < nF; ++f) {
1117       fieldSizes[f] = 0;
1118     }
1119     for (p = pStart; p < pEnd; ++p) {
1120       PetscInt gdof;
1121 
1122       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1123       if (gdof > 0) {
1124         for (f = 0; f < nF; ++f) {
1125           PetscInt fdof, fcdof;
1126 
1127           ierr           = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1128           ierr           = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1129           fieldSizes[f] += fdof-fcdof;
1130         }
1131       }
1132     }
1133     for (f = 0; f < nF; ++f) {
1134       ierr          = PetscMalloc1(fieldSizes[f], &fieldIndices[f]);CHKERRQ(ierr);
1135       fieldSizes[f] = 0;
1136     }
1137     for (p = pStart; p < pEnd; ++p) {
1138       PetscInt gdof, goff;
1139 
1140       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1141       if (gdof > 0) {
1142         ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1143         for (f = 0; f < nF; ++f) {
1144           PetscInt fdof, fcdof, fc;
1145 
1146           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1147           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1148           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1149             fieldIndices[f][fieldSizes[f]] = goff++;
1150           }
1151         }
1152       }
1153     }
1154     if (numFields) *numFields = nF;
1155     if (fieldNames) {
1156       ierr = PetscMalloc1(nF, fieldNames);CHKERRQ(ierr);
1157       for (f = 0; f < nF; ++f) {
1158         const char *fieldName;
1159 
1160         ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1161         ierr = PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);CHKERRQ(ierr);
1162       }
1163     }
1164     if (fields) {
1165       ierr = PetscMalloc1(nF, fields);CHKERRQ(ierr);
1166       for (f = 0; f < nF; ++f) {
1167         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);CHKERRQ(ierr);
1168       }
1169     }
1170     ierr = PetscFree2(fieldSizes,fieldIndices);CHKERRQ(ierr);
1171   } else if (dm->ops->createfieldis) {
1172     ierr = (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);CHKERRQ(ierr);
1173   }
1174   PetscFunctionReturn(0);
1175 }
1176 
1177 
1178 #undef __FUNCT__
1179 #define __FUNCT__ "DMCreateFieldDecomposition"
1180 /*@C
1181   DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1182                           corresponding to different fields: each IS contains the global indices of the dofs of the
1183                           corresponding field. The optional list of DMs define the DM for each subproblem.
1184                           Generalizes DMCreateFieldIS().
1185 
1186   Not collective
1187 
1188   Input Parameter:
1189 . dm - the DM object
1190 
1191   Output Parameters:
1192 + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1193 . namelist  - The name for each field (or NULL if not requested)
1194 . islist    - The global indices for each field (or NULL if not requested)
1195 - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1196 
1197   Level: intermediate
1198 
1199   Notes:
1200   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1201   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1202   and all of the arrays should be freed with PetscFree().
1203 
1204 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1205 @*/
1206 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1207 {
1208   PetscErrorCode ierr;
1209 
1210   PetscFunctionBegin;
1211   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1212   if (len) {
1213     PetscValidPointer(len,2);
1214     *len = 0;
1215   }
1216   if (namelist) {
1217     PetscValidPointer(namelist,3);
1218     *namelist = 0;
1219   }
1220   if (islist) {
1221     PetscValidPointer(islist,4);
1222     *islist = 0;
1223   }
1224   if (dmlist) {
1225     PetscValidPointer(dmlist,5);
1226     *dmlist = 0;
1227   }
1228   /*
1229    Is it a good idea to apply the following check across all impls?
1230    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1231    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1232    */
1233   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1234   if (!dm->ops->createfielddecomposition) {
1235     PetscSection section;
1236     PetscInt     numFields, f;
1237 
1238     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1239     if (section) {ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);}
1240     if (section && numFields && dm->ops->createsubdm) {
1241       *len = numFields;
1242       if (namelist) {ierr = PetscMalloc1(numFields,namelist);CHKERRQ(ierr);}
1243       if (islist)   {ierr = PetscMalloc1(numFields,islist);CHKERRQ(ierr);}
1244       if (dmlist)   {ierr = PetscMalloc1(numFields,dmlist);CHKERRQ(ierr);}
1245       for (f = 0; f < numFields; ++f) {
1246         const char *fieldName;
1247 
1248         ierr = DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);CHKERRQ(ierr);
1249         if (namelist) {
1250           ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1251           ierr = PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);CHKERRQ(ierr);
1252         }
1253       }
1254     } else {
1255       ierr = DMCreateFieldIS(dm, len, namelist, islist);CHKERRQ(ierr);
1256       /* By default there are no DMs associated with subproblems. */
1257       if (dmlist) *dmlist = NULL;
1258     }
1259   } else {
1260     ierr = (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);CHKERRQ(ierr);
1261   }
1262   PetscFunctionReturn(0);
1263 }
1264 
1265 #undef __FUNCT__
1266 #define __FUNCT__ "DMCreateSubDM"
1267 /*@C
1268   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1269                   The fields are defined by DMCreateFieldIS().
1270 
1271   Not collective
1272 
1273   Input Parameters:
1274 + dm - the DM object
1275 . numFields - number of fields in this subproblem
1276 - len       - The number of subproblems in the decomposition (or NULL if not requested)
1277 
1278   Output Parameters:
1279 . is - The global indices for the subproblem
1280 - dm - The DM for the subproblem
1281 
1282   Level: intermediate
1283 
1284 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1285 @*/
1286 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1287 {
1288   PetscErrorCode ierr;
1289 
1290   PetscFunctionBegin;
1291   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1292   PetscValidPointer(fields,3);
1293   if (is) PetscValidPointer(is,4);
1294   if (subdm) PetscValidPointer(subdm,5);
1295   if (dm->ops->createsubdm) {
1296     ierr = (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1297   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1298   PetscFunctionReturn(0);
1299 }
1300 
1301 
1302 #undef __FUNCT__
1303 #define __FUNCT__ "DMCreateDomainDecomposition"
1304 /*@C
1305   DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1306                           corresponding to restrictions to pairs nested subdomains: each IS contains the global
1307                           indices of the dofs of the corresponding subdomains.  The inner subdomains conceptually
1308                           define a nonoverlapping covering, while outer subdomains can overlap.
1309                           The optional list of DMs define the DM for each subproblem.
1310 
1311   Not collective
1312 
1313   Input Parameter:
1314 . dm - the DM object
1315 
1316   Output Parameters:
1317 + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1318 . namelist    - The name for each subdomain (or NULL if not requested)
1319 . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1320 . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1321 - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1322 
1323   Level: intermediate
1324 
1325   Notes:
1326   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1327   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1328   and all of the arrays should be freed with PetscFree().
1329 
1330 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1331 @*/
1332 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1333 {
1334   PetscErrorCode      ierr;
1335   DMSubDomainHookLink link;
1336   PetscInt            i,l;
1337 
1338   PetscFunctionBegin;
1339   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1340   if (len)           {PetscValidPointer(len,2);            *len         = 0;}
1341   if (namelist)      {PetscValidPointer(namelist,3);       *namelist    = NULL;}
1342   if (innerislist)   {PetscValidPointer(innerislist,4);    *innerislist = NULL;}
1343   if (outerislist)   {PetscValidPointer(outerislist,5);    *outerislist = NULL;}
1344   if (dmlist)        {PetscValidPointer(dmlist,6);         *dmlist      = NULL;}
1345   /*
1346    Is it a good idea to apply the following check across all impls?
1347    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1348    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1349    */
1350   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1351   if (dm->ops->createdomaindecomposition) {
1352     ierr = (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);CHKERRQ(ierr);
1353     /* copy subdomain hooks and context over to the subdomain DMs */
1354     if (dmlist) {
1355       for (i = 0; i < l; i++) {
1356         for (link=dm->subdomainhook; link; link=link->next) {
1357           if (link->ddhook) {ierr = (*link->ddhook)(dm,(*dmlist)[i],link->ctx);CHKERRQ(ierr);}
1358         }
1359         (*dmlist)[i]->ctx = dm->ctx;
1360       }
1361     }
1362     if (len) *len = l;
1363   }
1364   PetscFunctionReturn(0);
1365 }
1366 
1367 
1368 #undef __FUNCT__
1369 #define __FUNCT__ "DMCreateDomainDecompositionScatters"
1370 /*@C
1371   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
1372 
1373   Not collective
1374 
1375   Input Parameters:
1376 + dm - the DM object
1377 . n  - the number of subdomain scatters
1378 - subdms - the local subdomains
1379 
1380   Output Parameters:
1381 + n     - the number of scatters returned
1382 . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1383 . oscat - scatter from global vector to overlapping global vector entries on subdomain
1384 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
1385 
1386   Notes: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
1387   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
1388   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
1389   solution and residual data.
1390 
1391   Level: developer
1392 
1393 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1394 @*/
1395 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1396 {
1397   PetscErrorCode ierr;
1398 
1399   PetscFunctionBegin;
1400   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1401   PetscValidPointer(subdms,3);
1402   if (dm->ops->createddscatters) {
1403     ierr = (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);CHKERRQ(ierr);
1404   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionLocalScatter implementation defined");
1405   PetscFunctionReturn(0);
1406 }
1407 
1408 #undef __FUNCT__
1409 #define __FUNCT__ "DMRefine"
1410 /*@
1411   DMRefine - Refines a DM object
1412 
1413   Collective on DM
1414 
1415   Input Parameter:
1416 + dm   - the DM object
1417 - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1418 
1419   Output Parameter:
1420 . dmf - the refined DM, or NULL
1421 
1422   Note: If no refinement was done, the return value is NULL
1423 
1424   Level: developer
1425 
1426 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1427 @*/
1428 PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1429 {
1430   PetscErrorCode   ierr;
1431   DMRefineHookLink link;
1432 
1433   PetscFunctionBegin;
1434   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1435   ierr = (*dm->ops->refine)(dm,comm,dmf);CHKERRQ(ierr);
1436   if (*dmf) {
1437     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
1438 
1439     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);CHKERRQ(ierr);
1440 
1441     (*dmf)->ctx       = dm->ctx;
1442     (*dmf)->leveldown = dm->leveldown;
1443     (*dmf)->levelup   = dm->levelup + 1;
1444 
1445     ierr = DMSetMatType(*dmf,dm->mattype);CHKERRQ(ierr);
1446     for (link=dm->refinehook; link; link=link->next) {
1447       if (link->refinehook) {
1448         ierr = (*link->refinehook)(dm,*dmf,link->ctx);CHKERRQ(ierr);
1449       }
1450     }
1451   }
1452   PetscFunctionReturn(0);
1453 }
1454 
1455 #undef __FUNCT__
1456 #define __FUNCT__ "DMRefineHookAdd"
1457 /*@C
1458    DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
1459 
1460    Logically Collective
1461 
1462    Input Arguments:
1463 +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
1464 .  refinehook - function to run when setting up a coarser level
1465 .  interphook - function to run to update data on finer levels (once per SNESSolve())
1466 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1467 
1468    Calling sequence of refinehook:
1469 $    refinehook(DM coarse,DM fine,void *ctx);
1470 
1471 +  coarse - coarse level DM
1472 .  fine - fine level DM to interpolate problem to
1473 -  ctx - optional user-defined function context
1474 
1475    Calling sequence for interphook:
1476 $    interphook(DM coarse,Mat interp,DM fine,void *ctx)
1477 
1478 +  coarse - coarse level DM
1479 .  interp - matrix interpolating a coarse-level solution to the finer grid
1480 .  fine - fine level DM to update
1481 -  ctx - optional user-defined function context
1482 
1483    Level: advanced
1484 
1485    Notes:
1486    This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
1487 
1488    If this function is called multiple times, the hooks will be run in the order they are added.
1489 
1490    This function is currently not available from Fortran.
1491 
1492 .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1493 @*/
1494 PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1495 {
1496   PetscErrorCode   ierr;
1497   DMRefineHookLink link,*p;
1498 
1499   PetscFunctionBegin;
1500   PetscValidHeaderSpecific(coarse,DM_CLASSID,1);
1501   for (p=&coarse->refinehook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1502   ierr             = PetscMalloc(sizeof(struct _DMRefineHookLink),&link);CHKERRQ(ierr);
1503   link->refinehook = refinehook;
1504   link->interphook = interphook;
1505   link->ctx        = ctx;
1506   link->next       = NULL;
1507   *p               = link;
1508   PetscFunctionReturn(0);
1509 }
1510 
1511 #undef __FUNCT__
1512 #define __FUNCT__ "DMInterpolate"
1513 /*@
1514    DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
1515 
1516    Collective if any hooks are
1517 
1518    Input Arguments:
1519 +  coarse - coarser DM to use as a base
1520 .  restrct - interpolation matrix, apply using MatInterpolate()
1521 -  fine - finer DM to update
1522 
1523    Level: developer
1524 
1525 .seealso: DMRefineHookAdd(), MatInterpolate()
1526 @*/
1527 PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1528 {
1529   PetscErrorCode   ierr;
1530   DMRefineHookLink link;
1531 
1532   PetscFunctionBegin;
1533   for (link=fine->refinehook; link; link=link->next) {
1534     if (link->interphook) {
1535       ierr = (*link->interphook)(coarse,interp,fine,link->ctx);CHKERRQ(ierr);
1536     }
1537   }
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 #undef __FUNCT__
1542 #define __FUNCT__ "DMGetRefineLevel"
1543 /*@
1544     DMGetRefineLevel - Get's the number of refinements that have generated this DM.
1545 
1546     Not Collective
1547 
1548     Input Parameter:
1549 .   dm - the DM object
1550 
1551     Output Parameter:
1552 .   level - number of refinements
1553 
1554     Level: developer
1555 
1556 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1557 
1558 @*/
1559 PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1560 {
1561   PetscFunctionBegin;
1562   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1563   *level = dm->levelup;
1564   PetscFunctionReturn(0);
1565 }
1566 
1567 #undef __FUNCT__
1568 #define __FUNCT__ "DMGlobalToLocalHookAdd"
1569 /*@C
1570    DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
1571 
1572    Logically Collective
1573 
1574    Input Arguments:
1575 +  dm - the DM
1576 .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
1577 .  endhook - function to run after DMGlobalToLocalEnd() has completed
1578 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1579 
1580    Calling sequence for beginhook:
1581 $    beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1582 
1583 +  dm - global DM
1584 .  g - global vector
1585 .  mode - mode
1586 .  l - local vector
1587 -  ctx - optional user-defined function context
1588 
1589 
1590    Calling sequence for endhook:
1591 $    endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1592 
1593 +  global - global DM
1594 -  ctx - optional user-defined function context
1595 
1596    Level: advanced
1597 
1598 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1599 @*/
1600 PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1601 {
1602   PetscErrorCode          ierr;
1603   DMGlobalToLocalHookLink link,*p;
1604 
1605   PetscFunctionBegin;
1606   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1607   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1608   ierr            = PetscMalloc(sizeof(struct _DMGlobalToLocalHookLink),&link);CHKERRQ(ierr);
1609   link->beginhook = beginhook;
1610   link->endhook   = endhook;
1611   link->ctx       = ctx;
1612   link->next      = NULL;
1613   *p              = link;
1614   PetscFunctionReturn(0);
1615 }
1616 
1617 #undef __FUNCT__
1618 #define __FUNCT__ "DMGlobalToLocalBegin"
1619 /*@
1620     DMGlobalToLocalBegin - Begins updating local vectors from global vector
1621 
1622     Neighbor-wise Collective on DM
1623 
1624     Input Parameters:
1625 +   dm - the DM object
1626 .   g - the global vector
1627 .   mode - INSERT_VALUES or ADD_VALUES
1628 -   l - the local vector
1629 
1630 
1631     Level: beginner
1632 
1633 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1634 
1635 @*/
1636 PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1637 {
1638   PetscSF                 sf;
1639   PetscErrorCode          ierr;
1640   DMGlobalToLocalHookLink link;
1641 
1642   PetscFunctionBegin;
1643   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1644   for (link=dm->gtolhook; link; link=link->next) {
1645     if (link->beginhook) {
1646       ierr = (*link->beginhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);
1647     }
1648   }
1649   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1650   if (sf) {
1651     PetscScalar *lArray, *gArray;
1652 
1653     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1654     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1655     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1656     ierr = PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1657     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1658     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1659   } else {
1660     ierr = (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1661   }
1662   PetscFunctionReturn(0);
1663 }
1664 
1665 #undef __FUNCT__
1666 #define __FUNCT__ "DMGlobalToLocalEnd"
1667 /*@
1668     DMGlobalToLocalEnd - Ends updating local vectors from global vector
1669 
1670     Neighbor-wise Collective on DM
1671 
1672     Input Parameters:
1673 +   dm - the DM object
1674 .   g - the global vector
1675 .   mode - INSERT_VALUES or ADD_VALUES
1676 -   l - the local vector
1677 
1678 
1679     Level: beginner
1680 
1681 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1682 
1683 @*/
1684 PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1685 {
1686   PetscSF                 sf;
1687   PetscErrorCode          ierr;
1688   PetscScalar             *lArray, *gArray;
1689   DMGlobalToLocalHookLink link;
1690 
1691   PetscFunctionBegin;
1692   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1693   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1694   if (sf) {
1695     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1696 
1697     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1698     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1699     ierr = PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1700     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1701     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1702   } else {
1703     ierr = (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1704   }
1705   for (link=dm->gtolhook; link; link=link->next) {
1706     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1707   }
1708   PetscFunctionReturn(0);
1709 }
1710 
1711 #undef __FUNCT__
1712 #define __FUNCT__ "DMLocalToGlobalHookAdd"
1713 /*@C
1714    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
1715 
1716    Logically Collective
1717 
1718    Input Arguments:
1719 +  dm - the DM
1720 .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
1721 .  endhook - function to run after DMLocalToGlobalEnd() has completed
1722 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1723 
1724    Calling sequence for beginhook:
1725 $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1726 
1727 +  dm - global DM
1728 .  l - local vector
1729 .  mode - mode
1730 .  g - global vector
1731 -  ctx - optional user-defined function context
1732 
1733 
1734    Calling sequence for endhook:
1735 $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1736 
1737 +  global - global DM
1738 .  l - local vector
1739 .  mode - mode
1740 .  g - global vector
1741 -  ctx - optional user-defined function context
1742 
1743    Level: advanced
1744 
1745 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1746 @*/
1747 PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1748 {
1749   PetscErrorCode          ierr;
1750   DMLocalToGlobalHookLink link,*p;
1751 
1752   PetscFunctionBegin;
1753   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1754   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1755   ierr            = PetscMalloc(sizeof(struct _DMLocalToGlobalHookLink),&link);CHKERRQ(ierr);
1756   link->beginhook = beginhook;
1757   link->endhook   = endhook;
1758   link->ctx       = ctx;
1759   link->next      = NULL;
1760   *p              = link;
1761   PetscFunctionReturn(0);
1762 }
1763 
1764 #undef __FUNCT__
1765 #define __FUNCT__ "DMLocalToGlobalBegin"
1766 /*@
1767     DMLocalToGlobalBegin - updates global vectors from local vectors
1768 
1769     Neighbor-wise Collective on DM
1770 
1771     Input Parameters:
1772 +   dm - the DM object
1773 .   l - the local vector
1774 .   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
1775            base point.
1776 - - the global vector
1777 
1778     Notes: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation. If you would like to simply add the non-ghosted values in the local
1779            array into the global array you need to either (1) zero the ghosted locations and use ADD_VALUES or (2) use INSERT_VALUES into a work global array and then add the work
1780            global array to the final global array with VecAXPY().
1781 
1782     Level: beginner
1783 
1784 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
1785 
1786 @*/
1787 PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
1788 {
1789   PetscSF                 sf;
1790   PetscErrorCode          ierr;
1791   DMLocalToGlobalHookLink link;
1792 
1793   PetscFunctionBegin;
1794   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1795   for (link=dm->ltoghook; link; link=link->next) {
1796     if (link->beginhook) {
1797       ierr = (*link->beginhook)(dm,l,mode,g,link->ctx);CHKERRQ(ierr);
1798     }
1799   }
1800   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1801   if (sf) {
1802     MPI_Op      op;
1803     PetscScalar *lArray, *gArray;
1804 
1805     switch (mode) {
1806     case INSERT_VALUES:
1807     case INSERT_ALL_VALUES:
1808       op = MPIU_REPLACE; break;
1809     case ADD_VALUES:
1810     case ADD_ALL_VALUES:
1811       op = MPI_SUM; break;
1812     default:
1813       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1814     }
1815     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1816     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1817     ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, op);CHKERRQ(ierr);
1818     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1819     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1820   } else {
1821     ierr = (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1822   }
1823   PetscFunctionReturn(0);
1824 }
1825 
1826 #undef __FUNCT__
1827 #define __FUNCT__ "DMLocalToGlobalEnd"
1828 /*@
1829     DMLocalToGlobalEnd - updates global vectors from local vectors
1830 
1831     Neighbor-wise Collective on DM
1832 
1833     Input Parameters:
1834 +   dm - the DM object
1835 .   l - the local vector
1836 .   mode - INSERT_VALUES or ADD_VALUES
1837 -   g - the global vector
1838 
1839 
1840     Level: beginner
1841 
1842 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
1843 
1844 @*/
1845 PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
1846 {
1847   PetscSF        sf;
1848   PetscErrorCode ierr;
1849   DMLocalToGlobalHookLink link;
1850 
1851   PetscFunctionBegin;
1852   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1853   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1854   if (sf) {
1855     MPI_Op      op;
1856     PetscScalar *lArray, *gArray;
1857 
1858     switch (mode) {
1859     case INSERT_VALUES:
1860     case INSERT_ALL_VALUES:
1861       op = MPIU_REPLACE; break;
1862     case ADD_VALUES:
1863     case ADD_ALL_VALUES:
1864       op = MPI_SUM; break;
1865     default:
1866       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1867     }
1868     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1869     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1870     ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, op);CHKERRQ(ierr);
1871     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1872     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1873   } else {
1874     ierr = (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1875   }
1876   for (link=dm->ltoghook; link; link=link->next) {
1877     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1878   }
1879   PetscFunctionReturn(0);
1880 }
1881 
1882 #undef __FUNCT__
1883 #define __FUNCT__ "DMLocalToLocalBegin"
1884 /*@
1885    DMLocalToLocalBegin - Maps from a local vector (including ghost points
1886    that contain irrelevant values) to another local vector where the ghost
1887    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
1888 
1889    Neighbor-wise Collective on DM and Vec
1890 
1891    Input Parameters:
1892 +  dm - the DM object
1893 .  g - the original local vector
1894 -  mode - one of INSERT_VALUES or ADD_VALUES
1895 
1896    Output Parameter:
1897 .  l  - the local vector with correct ghost values
1898 
1899    Level: intermediate
1900 
1901    Notes:
1902    The local vectors used here need not be the same as those
1903    obtained from DMCreateLocalVector(), BUT they
1904    must have the same parallel data layout; they could, for example, be
1905    obtained with VecDuplicate() from the DM originating vectors.
1906 
1907 .keywords: DM, local-to-local, begin
1908 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1909 
1910 @*/
1911 PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1912 {
1913   PetscErrorCode          ierr;
1914 
1915   PetscFunctionBegin;
1916   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1917   ierr = (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1918   PetscFunctionReturn(0);
1919 }
1920 
1921 #undef __FUNCT__
1922 #define __FUNCT__ "DMLocalToLocalEnd"
1923 /*@
1924    DMLocalToLocalEnd - Maps from a local vector (including ghost points
1925    that contain irrelevant values) to another local vector where the ghost
1926    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
1927 
1928    Neighbor-wise Collective on DM and Vec
1929 
1930    Input Parameters:
1931 +  da - the DM object
1932 .  g - the original local vector
1933 -  mode - one of INSERT_VALUES or ADD_VALUES
1934 
1935    Output Parameter:
1936 .  l  - the local vector with correct ghost values
1937 
1938    Level: intermediate
1939 
1940    Notes:
1941    The local vectors used here need not be the same as those
1942    obtained from DMCreateLocalVector(), BUT they
1943    must have the same parallel data layout; they could, for example, be
1944    obtained with VecDuplicate() from the DM originating vectors.
1945 
1946 .keywords: DM, local-to-local, end
1947 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1948 
1949 @*/
1950 PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1951 {
1952   PetscErrorCode          ierr;
1953 
1954   PetscFunctionBegin;
1955   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1956   ierr = (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1957   PetscFunctionReturn(0);
1958 }
1959 
1960 
1961 #undef __FUNCT__
1962 #define __FUNCT__ "DMCoarsen"
1963 /*@
1964     DMCoarsen - Coarsens a DM object
1965 
1966     Collective on DM
1967 
1968     Input Parameter:
1969 +   dm - the DM object
1970 -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1971 
1972     Output Parameter:
1973 .   dmc - the coarsened DM
1974 
1975     Level: developer
1976 
1977 .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1978 
1979 @*/
1980 PetscErrorCode  DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
1981 {
1982   PetscErrorCode    ierr;
1983   DMCoarsenHookLink link;
1984 
1985   PetscFunctionBegin;
1986   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1987   ierr                      = (*dm->ops->coarsen)(dm, comm, dmc);CHKERRQ(ierr);
1988   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
1989   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
1990   (*dmc)->ctx               = dm->ctx;
1991   (*dmc)->levelup           = dm->levelup;
1992   (*dmc)->leveldown         = dm->leveldown + 1;
1993   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
1994   for (link=dm->coarsenhook; link; link=link->next) {
1995     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
1996   }
1997   PetscFunctionReturn(0);
1998 }
1999 
2000 #undef __FUNCT__
2001 #define __FUNCT__ "DMCoarsenHookAdd"
2002 /*@C
2003    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2004 
2005    Logically Collective
2006 
2007    Input Arguments:
2008 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2009 .  coarsenhook - function to run when setting up a coarser level
2010 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2011 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2012 
2013    Calling sequence of coarsenhook:
2014 $    coarsenhook(DM fine,DM coarse,void *ctx);
2015 
2016 +  fine - fine level DM
2017 .  coarse - coarse level DM to restrict problem to
2018 -  ctx - optional user-defined function context
2019 
2020    Calling sequence for restricthook:
2021 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2022 
2023 +  fine - fine level DM
2024 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2025 .  rscale - scaling vector for restriction
2026 .  inject - matrix restricting by injection
2027 .  coarse - coarse level DM to update
2028 -  ctx - optional user-defined function context
2029 
2030    Level: advanced
2031 
2032    Notes:
2033    This function is only needed if auxiliary data needs to be set up on coarse grids.
2034 
2035    If this function is called multiple times, the hooks will be run in the order they are added.
2036 
2037    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2038    extract the finest level information from its context (instead of from the SNES).
2039 
2040    This function is currently not available from Fortran.
2041 
2042 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2043 @*/
2044 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2045 {
2046   PetscErrorCode    ierr;
2047   DMCoarsenHookLink link,*p;
2048 
2049   PetscFunctionBegin;
2050   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2051   for (p=&fine->coarsenhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2052   ierr               = PetscMalloc(sizeof(struct _DMCoarsenHookLink),&link);CHKERRQ(ierr);
2053   link->coarsenhook  = coarsenhook;
2054   link->restricthook = restricthook;
2055   link->ctx          = ctx;
2056   link->next         = NULL;
2057   *p                 = link;
2058   PetscFunctionReturn(0);
2059 }
2060 
2061 #undef __FUNCT__
2062 #define __FUNCT__ "DMRestrict"
2063 /*@
2064    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2065 
2066    Collective if any hooks are
2067 
2068    Input Arguments:
2069 +  fine - finer DM to use as a base
2070 .  restrct - restriction matrix, apply using MatRestrict()
2071 .  inject - injection matrix, also use MatRestrict()
2072 -  coarse - coarer DM to update
2073 
2074    Level: developer
2075 
2076 .seealso: DMCoarsenHookAdd(), MatRestrict()
2077 @*/
2078 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2079 {
2080   PetscErrorCode    ierr;
2081   DMCoarsenHookLink link;
2082 
2083   PetscFunctionBegin;
2084   for (link=fine->coarsenhook; link; link=link->next) {
2085     if (link->restricthook) {
2086       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2087     }
2088   }
2089   PetscFunctionReturn(0);
2090 }
2091 
2092 #undef __FUNCT__
2093 #define __FUNCT__ "DMSubDomainHookAdd"
2094 /*@C
2095    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2096 
2097    Logically Collective
2098 
2099    Input Arguments:
2100 +  global - global DM
2101 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2102 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2103 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2104 
2105 
2106    Calling sequence for ddhook:
2107 $    ddhook(DM global,DM block,void *ctx)
2108 
2109 +  global - global DM
2110 .  block  - block DM
2111 -  ctx - optional user-defined function context
2112 
2113    Calling sequence for restricthook:
2114 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2115 
2116 +  global - global DM
2117 .  out    - scatter to the outer (with ghost and overlap points) block vector
2118 .  in     - scatter to block vector values only owned locally
2119 .  block  - block DM
2120 -  ctx - optional user-defined function context
2121 
2122    Level: advanced
2123 
2124    Notes:
2125    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2126 
2127    If this function is called multiple times, the hooks will be run in the order they are added.
2128 
2129    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2130    extract the global information from its context (instead of from the SNES).
2131 
2132    This function is currently not available from Fortran.
2133 
2134 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2135 @*/
2136 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2137 {
2138   PetscErrorCode      ierr;
2139   DMSubDomainHookLink link,*p;
2140 
2141   PetscFunctionBegin;
2142   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2143   for (p=&global->subdomainhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2144   ierr               = PetscMalloc(sizeof(struct _DMSubDomainHookLink),&link);CHKERRQ(ierr);
2145   link->restricthook = restricthook;
2146   link->ddhook       = ddhook;
2147   link->ctx          = ctx;
2148   link->next         = NULL;
2149   *p                 = link;
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMSubDomainRestrict"
2155 /*@
2156    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2157 
2158    Collective if any hooks are
2159 
2160    Input Arguments:
2161 +  fine - finer DM to use as a base
2162 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2163 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2164 -  coarse - coarer DM to update
2165 
2166    Level: developer
2167 
2168 .seealso: DMCoarsenHookAdd(), MatRestrict()
2169 @*/
2170 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2171 {
2172   PetscErrorCode      ierr;
2173   DMSubDomainHookLink link;
2174 
2175   PetscFunctionBegin;
2176   for (link=global->subdomainhook; link; link=link->next) {
2177     if (link->restricthook) {
2178       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2179     }
2180   }
2181   PetscFunctionReturn(0);
2182 }
2183 
2184 #undef __FUNCT__
2185 #define __FUNCT__ "DMGetCoarsenLevel"
2186 /*@
2187     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2188 
2189     Not Collective
2190 
2191     Input Parameter:
2192 .   dm - the DM object
2193 
2194     Output Parameter:
2195 .   level - number of coarsenings
2196 
2197     Level: developer
2198 
2199 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2200 
2201 @*/
2202 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2203 {
2204   PetscFunctionBegin;
2205   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2206   *level = dm->leveldown;
2207   PetscFunctionReturn(0);
2208 }
2209 
2210 
2211 
2212 #undef __FUNCT__
2213 #define __FUNCT__ "DMRefineHierarchy"
2214 /*@C
2215     DMRefineHierarchy - Refines a DM object, all levels at once
2216 
2217     Collective on DM
2218 
2219     Input Parameter:
2220 +   dm - the DM object
2221 -   nlevels - the number of levels of refinement
2222 
2223     Output Parameter:
2224 .   dmf - the refined DM hierarchy
2225 
2226     Level: developer
2227 
2228 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2229 
2230 @*/
2231 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2232 {
2233   PetscErrorCode ierr;
2234 
2235   PetscFunctionBegin;
2236   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2237   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2238   if (nlevels == 0) PetscFunctionReturn(0);
2239   if (dm->ops->refinehierarchy) {
2240     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2241   } else if (dm->ops->refine) {
2242     PetscInt i;
2243 
2244     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2245     for (i=1; i<nlevels; i++) {
2246       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2247     }
2248   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2249   PetscFunctionReturn(0);
2250 }
2251 
2252 #undef __FUNCT__
2253 #define __FUNCT__ "DMCoarsenHierarchy"
2254 /*@C
2255     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2256 
2257     Collective on DM
2258 
2259     Input Parameter:
2260 +   dm - the DM object
2261 -   nlevels - the number of levels of coarsening
2262 
2263     Output Parameter:
2264 .   dmc - the coarsened DM hierarchy
2265 
2266     Level: developer
2267 
2268 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2269 
2270 @*/
2271 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2272 {
2273   PetscErrorCode ierr;
2274 
2275   PetscFunctionBegin;
2276   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2277   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2278   if (nlevels == 0) PetscFunctionReturn(0);
2279   PetscValidPointer(dmc,3);
2280   if (dm->ops->coarsenhierarchy) {
2281     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2282   } else if (dm->ops->coarsen) {
2283     PetscInt i;
2284 
2285     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2286     for (i=1; i<nlevels; i++) {
2287       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2288     }
2289   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2290   PetscFunctionReturn(0);
2291 }
2292 
2293 #undef __FUNCT__
2294 #define __FUNCT__ "DMCreateAggregates"
2295 /*@
2296    DMCreateAggregates - Gets the aggregates that map between
2297    grids associated with two DMs.
2298 
2299    Collective on DM
2300 
2301    Input Parameters:
2302 +  dmc - the coarse grid DM
2303 -  dmf - the fine grid DM
2304 
2305    Output Parameters:
2306 .  rest - the restriction matrix (transpose of the projection matrix)
2307 
2308    Level: intermediate
2309 
2310 .keywords: interpolation, restriction, multigrid
2311 
2312 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2313 @*/
2314 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2315 {
2316   PetscErrorCode ierr;
2317 
2318   PetscFunctionBegin;
2319   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2320   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2321   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2322   PetscFunctionReturn(0);
2323 }
2324 
2325 #undef __FUNCT__
2326 #define __FUNCT__ "DMSetApplicationContextDestroy"
2327 /*@C
2328     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2329 
2330     Not Collective
2331 
2332     Input Parameters:
2333 +   dm - the DM object
2334 -   destroy - the destroy function
2335 
2336     Level: intermediate
2337 
2338 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2339 
2340 @*/
2341 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2342 {
2343   PetscFunctionBegin;
2344   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2345   dm->ctxdestroy = destroy;
2346   PetscFunctionReturn(0);
2347 }
2348 
2349 #undef __FUNCT__
2350 #define __FUNCT__ "DMSetApplicationContext"
2351 /*@
2352     DMSetApplicationContext - Set a user context into a DM object
2353 
2354     Not Collective
2355 
2356     Input Parameters:
2357 +   dm - the DM object
2358 -   ctx - the user context
2359 
2360     Level: intermediate
2361 
2362 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2363 
2364 @*/
2365 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2366 {
2367   PetscFunctionBegin;
2368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2369   dm->ctx = ctx;
2370   PetscFunctionReturn(0);
2371 }
2372 
2373 #undef __FUNCT__
2374 #define __FUNCT__ "DMGetApplicationContext"
2375 /*@
2376     DMGetApplicationContext - Gets a user context from a DM object
2377 
2378     Not Collective
2379 
2380     Input Parameter:
2381 .   dm - the DM object
2382 
2383     Output Parameter:
2384 .   ctx - the user context
2385 
2386     Level: intermediate
2387 
2388 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2389 
2390 @*/
2391 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2392 {
2393   PetscFunctionBegin;
2394   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2395   *(void**)ctx = dm->ctx;
2396   PetscFunctionReturn(0);
2397 }
2398 
2399 #undef __FUNCT__
2400 #define __FUNCT__ "DMSetVariableBounds"
2401 /*@C
2402     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2403 
2404     Logically Collective on DM
2405 
2406     Input Parameter:
2407 +   dm - the DM object
2408 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
2409 
2410     Level: intermediate
2411 
2412 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2413          DMSetJacobian()
2414 
2415 @*/
2416 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2417 {
2418   PetscFunctionBegin;
2419   dm->ops->computevariablebounds = f;
2420   PetscFunctionReturn(0);
2421 }
2422 
2423 #undef __FUNCT__
2424 #define __FUNCT__ "DMHasVariableBounds"
2425 /*@
2426     DMHasVariableBounds - does the DM object have a variable bounds function?
2427 
2428     Not Collective
2429 
2430     Input Parameter:
2431 .   dm - the DM object to destroy
2432 
2433     Output Parameter:
2434 .   flg - PETSC_TRUE if the variable bounds function exists
2435 
2436     Level: developer
2437 
2438 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2439 
2440 @*/
2441 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2442 {
2443   PetscFunctionBegin;
2444   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2445   PetscFunctionReturn(0);
2446 }
2447 
2448 #undef __FUNCT__
2449 #define __FUNCT__ "DMComputeVariableBounds"
2450 /*@C
2451     DMComputeVariableBounds - compute variable bounds used by SNESVI.
2452 
2453     Logically Collective on DM
2454 
2455     Input Parameters:
2456 +   dm - the DM object to destroy
2457 -   x  - current solution at which the bounds are computed
2458 
2459     Output parameters:
2460 +   xl - lower bound
2461 -   xu - upper bound
2462 
2463     Level: intermediate
2464 
2465 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2466 
2467 @*/
2468 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2469 {
2470   PetscErrorCode ierr;
2471 
2472   PetscFunctionBegin;
2473   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2474   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
2475   if (dm->ops->computevariablebounds) {
2476     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
2477   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMHasColoring"
2483 /*@
2484     DMHasColoring - does the DM object have a method of providing a coloring?
2485 
2486     Not Collective
2487 
2488     Input Parameter:
2489 .   dm - the DM object
2490 
2491     Output Parameter:
2492 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
2493 
2494     Level: developer
2495 
2496 .seealso DMHasFunction(), DMCreateColoring()
2497 
2498 @*/
2499 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2500 {
2501   PetscFunctionBegin;
2502   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 #undef  __FUNCT__
2507 #define __FUNCT__ "DMSetVec"
2508 /*@C
2509     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
2510 
2511     Collective on DM
2512 
2513     Input Parameter:
2514 +   dm - the DM object
2515 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
2516 
2517     Level: developer
2518 
2519 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2520 
2521 @*/
2522 PetscErrorCode  DMSetVec(DM dm,Vec x)
2523 {
2524   PetscErrorCode ierr;
2525 
2526   PetscFunctionBegin;
2527   if (x) {
2528     if (!dm->x) {
2529       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
2530     }
2531     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
2532   } else if (dm->x) {
2533     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
2534   }
2535   PetscFunctionReturn(0);
2536 }
2537 
2538 PetscFunctionList DMList              = NULL;
2539 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
2540 
2541 #undef __FUNCT__
2542 #define __FUNCT__ "DMSetType"
2543 /*@C
2544   DMSetType - Builds a DM, for a particular DM implementation.
2545 
2546   Collective on DM
2547 
2548   Input Parameters:
2549 + dm     - The DM object
2550 - method - The name of the DM type
2551 
2552   Options Database Key:
2553 . -dm_type <type> - Sets the DM type; use -help for a list of available types
2554 
2555   Notes:
2556   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
2557 
2558   Level: intermediate
2559 
2560 .keywords: DM, set, type
2561 .seealso: DMGetType(), DMCreate()
2562 @*/
2563 PetscErrorCode  DMSetType(DM dm, DMType method)
2564 {
2565   PetscErrorCode (*r)(DM);
2566   PetscBool      match;
2567   PetscErrorCode ierr;
2568 
2569   PetscFunctionBegin;
2570   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2571   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
2572   if (match) PetscFunctionReturn(0);
2573 
2574   if (!DMRegisterAllCalled) {ierr = DMRegisterAll();CHKERRQ(ierr);}
2575   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
2576   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
2577 
2578   if (dm->ops->destroy) {
2579     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
2580     dm->ops->destroy = NULL;
2581   }
2582   ierr = (*r)(dm);CHKERRQ(ierr);
2583   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
2584   PetscFunctionReturn(0);
2585 }
2586 
2587 #undef __FUNCT__
2588 #define __FUNCT__ "DMGetType"
2589 /*@C
2590   DMGetType - Gets the DM type name (as a string) from the DM.
2591 
2592   Not Collective
2593 
2594   Input Parameter:
2595 . dm  - The DM
2596 
2597   Output Parameter:
2598 . type - The DM type name
2599 
2600   Level: intermediate
2601 
2602 .keywords: DM, get, type, name
2603 .seealso: DMSetType(), DMCreate()
2604 @*/
2605 PetscErrorCode  DMGetType(DM dm, DMType *type)
2606 {
2607   PetscErrorCode ierr;
2608 
2609   PetscFunctionBegin;
2610   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2611   PetscValidPointer(type,2);
2612   if (!DMRegisterAllCalled) {
2613     ierr = DMRegisterAll();CHKERRQ(ierr);
2614   }
2615   *type = ((PetscObject)dm)->type_name;
2616   PetscFunctionReturn(0);
2617 }
2618 
2619 #undef __FUNCT__
2620 #define __FUNCT__ "DMConvert"
2621 /*@C
2622   DMConvert - Converts a DM to another DM, either of the same or different type.
2623 
2624   Collective on DM
2625 
2626   Input Parameters:
2627 + dm - the DM
2628 - newtype - new DM type (use "same" for the same type)
2629 
2630   Output Parameter:
2631 . M - pointer to new DM
2632 
2633   Notes:
2634   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
2635   the MPI communicator of the generated DM is always the same as the communicator
2636   of the input DM.
2637 
2638   Level: intermediate
2639 
2640 .seealso: DMCreate()
2641 @*/
2642 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
2643 {
2644   DM             B;
2645   char           convname[256];
2646   PetscBool      sametype, issame;
2647   PetscErrorCode ierr;
2648 
2649   PetscFunctionBegin;
2650   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2651   PetscValidType(dm,1);
2652   PetscValidPointer(M,3);
2653   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
2654   ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr);
2655   {
2656     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
2657 
2658     /*
2659        Order of precedence:
2660        1) See if a specialized converter is known to the current DM.
2661        2) See if a specialized converter is known to the desired DM class.
2662        3) See if a good general converter is registered for the desired class
2663        4) See if a good general converter is known for the current matrix.
2664        5) Use a really basic converter.
2665     */
2666 
2667     /* 1) See if a specialized converter is known to the current DM and the desired class */
2668     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2669     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2670     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2671     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2672     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2673     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
2674     if (conv) goto foundconv;
2675 
2676     /* 2)  See if a specialized converter is known to the desired DM class. */
2677     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
2678     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
2679     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2680     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2681     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2682     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2683     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2684     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
2685     if (conv) {
2686       ierr = DMDestroy(&B);CHKERRQ(ierr);
2687       goto foundconv;
2688     }
2689 
2690 #if 0
2691     /* 3) See if a good general converter is registered for the desired class */
2692     conv = B->ops->convertfrom;
2693     ierr = DMDestroy(&B);CHKERRQ(ierr);
2694     if (conv) goto foundconv;
2695 
2696     /* 4) See if a good general converter is known for the current matrix */
2697     if (dm->ops->convert) {
2698       conv = dm->ops->convert;
2699     }
2700     if (conv) goto foundconv;
2701 #endif
2702 
2703     /* 5) Use a really basic converter. */
2704     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
2705 
2706 foundconv:
2707     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2708     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
2709     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2710   }
2711   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
2712   PetscFunctionReturn(0);
2713 }
2714 
2715 /*--------------------------------------------------------------------------------------------------------------------*/
2716 
2717 #undef __FUNCT__
2718 #define __FUNCT__ "DMRegister"
2719 /*@C
2720   DMRegister -  Adds a new DM component implementation
2721 
2722   Not Collective
2723 
2724   Input Parameters:
2725 + name        - The name of a new user-defined creation routine
2726 - create_func - The creation routine itself
2727 
2728   Notes:
2729   DMRegister() may be called multiple times to add several user-defined DMs
2730 
2731 
2732   Sample usage:
2733 .vb
2734     DMRegister("my_da", MyDMCreate);
2735 .ve
2736 
2737   Then, your DM type can be chosen with the procedural interface via
2738 .vb
2739     DMCreate(MPI_Comm, DM *);
2740     DMSetType(DM,"my_da");
2741 .ve
2742    or at runtime via the option
2743 .vb
2744     -da_type my_da
2745 .ve
2746 
2747   Level: advanced
2748 
2749 .keywords: DM, register
2750 .seealso: DMRegisterAll(), DMRegisterDestroy()
2751 
2752 @*/
2753 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
2754 {
2755   PetscErrorCode ierr;
2756 
2757   PetscFunctionBegin;
2758   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
2759   PetscFunctionReturn(0);
2760 }
2761 
2762 #undef __FUNCT__
2763 #define __FUNCT__ "DMLoad"
2764 /*@C
2765   DMLoad - Loads a DM that has been stored in binary  with DMView().
2766 
2767   Collective on PetscViewer
2768 
2769   Input Parameters:
2770 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
2771            some related function before a call to DMLoad().
2772 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
2773            HDF5 file viewer, obtained from PetscViewerHDF5Open()
2774 
2775    Level: intermediate
2776 
2777   Notes:
2778    The type is determined by the data in the file, any type set into the DM before this call is ignored.
2779 
2780   Notes for advanced users:
2781   Most users should not need to know the details of the binary storage
2782   format, since DMLoad() and DMView() completely hide these details.
2783   But for anyone who's interested, the standard binary matrix storage
2784   format is
2785 .vb
2786      has not yet been determined
2787 .ve
2788 
2789 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
2790 @*/
2791 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
2792 {
2793   PetscBool      isbinary, ishdf5;
2794   PetscErrorCode ierr;
2795 
2796   PetscFunctionBegin;
2797   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
2798   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
2799   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
2800   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2801   if (isbinary) {
2802     PetscInt classid;
2803     char     type[256];
2804 
2805     ierr = PetscViewerBinaryRead(viewer,&classid,1,PETSC_INT);CHKERRQ(ierr);
2806     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
2807     ierr = PetscViewerBinaryRead(viewer,type,256,PETSC_CHAR);CHKERRQ(ierr);
2808     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
2809     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2810   } else if (ishdf5) {
2811     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2812   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
2813   PetscFunctionReturn(0);
2814 }
2815 
2816 /******************************** FEM Support **********************************/
2817 
2818 #undef __FUNCT__
2819 #define __FUNCT__ "DMPrintCellVector"
2820 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
2821 {
2822   PetscInt       f;
2823   PetscErrorCode ierr;
2824 
2825   PetscFunctionBegin;
2826   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2827   for (f = 0; f < len; ++f) {
2828     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
2829   }
2830   PetscFunctionReturn(0);
2831 }
2832 
2833 #undef __FUNCT__
2834 #define __FUNCT__ "DMPrintCellMatrix"
2835 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
2836 {
2837   PetscInt       f, g;
2838   PetscErrorCode ierr;
2839 
2840   PetscFunctionBegin;
2841   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2842   for (f = 0; f < rows; ++f) {
2843     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
2844     for (g = 0; g < cols; ++g) {
2845       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
2846     }
2847     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
2848   }
2849   PetscFunctionReturn(0);
2850 }
2851 
2852 #undef __FUNCT__
2853 #define __FUNCT__ "DMPrintLocalVec"
2854 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
2855 {
2856   PetscMPIInt    rank, numProcs;
2857   PetscInt       p;
2858   PetscErrorCode ierr;
2859 
2860   PetscFunctionBegin;
2861   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2862   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
2863   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
2864   for (p = 0; p < numProcs; ++p) {
2865     if (p == rank) {
2866       Vec x;
2867 
2868       ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
2869       ierr = VecCopy(X, x);CHKERRQ(ierr);
2870       ierr = VecChop(x, tol);CHKERRQ(ierr);
2871       ierr = VecView(x, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2872       ierr = VecDestroy(&x);CHKERRQ(ierr);
2873       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2874     }
2875     ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
2876   }
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMGetDefaultSection"
2882 /*@
2883   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
2884 
2885   Input Parameter:
2886 . dm - The DM
2887 
2888   Output Parameter:
2889 . section - The PetscSection
2890 
2891   Level: intermediate
2892 
2893   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
2894 
2895 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
2896 @*/
2897 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
2898 {
2899   PetscErrorCode ierr;
2900 
2901   PetscFunctionBegin;
2902   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2903   PetscValidPointer(section, 2);
2904   if (!dm->defaultSection && dm->ops->createdefaultsection) {ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);}
2905   *section = dm->defaultSection;
2906   PetscFunctionReturn(0);
2907 }
2908 
2909 #undef __FUNCT__
2910 #define __FUNCT__ "DMSetDefaultSection"
2911 /*@
2912   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
2913 
2914   Input Parameters:
2915 + dm - The DM
2916 - section - The PetscSection
2917 
2918   Level: intermediate
2919 
2920   Note: Any existing Section will be destroyed
2921 
2922 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
2923 @*/
2924 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
2925 {
2926   PetscInt       numFields;
2927   PetscInt       f;
2928   PetscErrorCode ierr;
2929 
2930   PetscFunctionBegin;
2931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2932   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
2933   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
2934   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
2935   dm->defaultSection = section;
2936   ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);
2937   if (numFields) {
2938     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
2939     for (f = 0; f < numFields; ++f) {
2940       PetscObject disc;
2941       const char *name;
2942 
2943       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
2944       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
2945       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
2946     }
2947   }
2948   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
2949   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
2950   PetscFunctionReturn(0);
2951 }
2952 
2953 #undef __FUNCT__
2954 #define __FUNCT__ "DMGetDefaultConstraints"
2955 /*@
2956   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
2957 
2958   Input Parameter:
2959 . dm - The DM
2960 
2961   Output Parameter:
2962 + 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.
2963 - 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.
2964 
2965   Level: advanced
2966 
2967   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
2968 
2969 .seealso: DMSetDefaultConstraints()
2970 @*/
2971 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
2972 {
2973   PetscErrorCode ierr;
2974 
2975   PetscFunctionBegin;
2976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2977   PetscValidPointer(section, 2);
2978   PetscValidPointer(mat, 3);
2979   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
2980   *section = dm->defaultConstraintSection;
2981   *mat = dm->defaultConstraintMat;
2982   PetscFunctionReturn(0);
2983 }
2984 
2985 #undef __FUNCT__
2986 #define __FUNCT__ "DMSetDefaultConstraints"
2987 /*@
2988   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
2989 
2990   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().
2991 
2992   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.
2993 
2994   Input Parameters:
2995 + dm - The DM
2996 + section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.
2997 - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section:  NULL indicates no constraints.
2998 
2999   Level: advanced
3000 
3001   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3002 
3003 .seealso: DMGetDefaultConstraints()
3004 @*/
3005 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3006 {
3007   PetscInt       numFields;
3008   PetscErrorCode ierr;
3009 
3010   PetscFunctionBegin;
3011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3012   if (section) {PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);}
3013   if (mat) {PetscValidHeaderSpecific(mat,MAT_CLASSID,3);}
3014   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3015   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3016   dm->defaultConstraintSection = section;
3017   ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);
3018   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3019   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3020   dm->defaultConstraintMat = mat;
3021   PetscFunctionReturn(0);
3022 }
3023 
3024 #undef __FUNCT__
3025 #define __FUNCT__ "DMGetDefaultGlobalSection"
3026 /*@
3027   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3028 
3029   Collective on DM
3030 
3031   Input Parameter:
3032 . dm - The DM
3033 
3034   Output Parameter:
3035 . section - The PetscSection
3036 
3037   Level: intermediate
3038 
3039   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3040 
3041 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3042 @*/
3043 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3044 {
3045   PetscErrorCode ierr;
3046 
3047   PetscFunctionBegin;
3048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3049   PetscValidPointer(section, 2);
3050   if (!dm->defaultGlobalSection) {
3051     PetscSection s;
3052 
3053     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3054     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3055     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3056     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3057     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3058     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3059   }
3060   *section = dm->defaultGlobalSection;
3061   PetscFunctionReturn(0);
3062 }
3063 
3064 #undef __FUNCT__
3065 #define __FUNCT__ "DMSetDefaultGlobalSection"
3066 /*@
3067   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3068 
3069   Input Parameters:
3070 + dm - The DM
3071 - section - The PetscSection, or NULL
3072 
3073   Level: intermediate
3074 
3075   Note: Any existing Section will be destroyed
3076 
3077 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3078 @*/
3079 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3080 {
3081   PetscErrorCode ierr;
3082 
3083   PetscFunctionBegin;
3084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3085   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3086   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3087   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3088   dm->defaultGlobalSection = section;
3089   PetscFunctionReturn(0);
3090 }
3091 
3092 #undef __FUNCT__
3093 #define __FUNCT__ "DMGetDefaultSF"
3094 /*@
3095   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3096   it is created from the default PetscSection layouts in the DM.
3097 
3098   Input Parameter:
3099 . dm - The DM
3100 
3101   Output Parameter:
3102 . sf - The PetscSF
3103 
3104   Level: intermediate
3105 
3106   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3107 
3108 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3109 @*/
3110 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3111 {
3112   PetscInt       nroots;
3113   PetscErrorCode ierr;
3114 
3115   PetscFunctionBegin;
3116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3117   PetscValidPointer(sf, 2);
3118   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3119   if (nroots < 0) {
3120     PetscSection section, gSection;
3121 
3122     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3123     if (section) {
3124       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3125       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3126     } else {
3127       *sf = NULL;
3128       PetscFunctionReturn(0);
3129     }
3130   }
3131   *sf = dm->defaultSF;
3132   PetscFunctionReturn(0);
3133 }
3134 
3135 #undef __FUNCT__
3136 #define __FUNCT__ "DMSetDefaultSF"
3137 /*@
3138   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3139 
3140   Input Parameters:
3141 + dm - The DM
3142 - sf - The PetscSF
3143 
3144   Level: intermediate
3145 
3146   Note: Any previous SF is destroyed
3147 
3148 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3149 @*/
3150 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3151 {
3152   PetscErrorCode ierr;
3153 
3154   PetscFunctionBegin;
3155   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3156   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3157   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3158   dm->defaultSF = sf;
3159   PetscFunctionReturn(0);
3160 }
3161 
3162 #undef __FUNCT__
3163 #define __FUNCT__ "DMCreateDefaultSF"
3164 /*@C
3165   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3166   describing the data layout.
3167 
3168   Input Parameters:
3169 + dm - The DM
3170 . localSection - PetscSection describing the local data layout
3171 - globalSection - PetscSection describing the global data layout
3172 
3173   Level: intermediate
3174 
3175 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3176 @*/
3177 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3178 {
3179   MPI_Comm       comm;
3180   PetscLayout    layout;
3181   const PetscInt *ranges;
3182   PetscInt       *local;
3183   PetscSFNode    *remote;
3184   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3185   PetscMPIInt    size, rank;
3186   PetscErrorCode ierr;
3187 
3188   PetscFunctionBegin;
3189   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3191   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3192   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3193   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3194   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3195   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3196   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3197   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3198   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3199   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3200   for (p = pStart; p < pEnd; ++p) {
3201     PetscInt gdof, gcdof;
3202 
3203     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3204     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3205     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));
3206     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3207   }
3208   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3209   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3210   for (p = pStart, l = 0; p < pEnd; ++p) {
3211     const PetscInt *cind;
3212     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3213 
3214     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3215     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3216     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3217     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3218     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3219     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3220     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3221     if (!gdof) continue; /* Censored point */
3222     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3223     if (gsize != dof-cdof) {
3224       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);
3225       cdof = 0; /* Ignore constraints */
3226     }
3227     for (d = 0, c = 0; d < dof; ++d) {
3228       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3229       local[l+d-c] = off+d;
3230     }
3231     if (gdof < 0) {
3232       for (d = 0; d < gsize; ++d, ++l) {
3233         PetscInt offset = -(goff+1) + d, r;
3234 
3235         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3236         if (r < 0) r = -(r+2);
3237         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);
3238         remote[l].rank  = r;
3239         remote[l].index = offset - ranges[r];
3240       }
3241     } else {
3242       for (d = 0; d < gsize; ++d, ++l) {
3243         remote[l].rank  = rank;
3244         remote[l].index = goff+d - ranges[rank];
3245       }
3246     }
3247   }
3248   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3249   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3250   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3251   PetscFunctionReturn(0);
3252 }
3253 
3254 #undef __FUNCT__
3255 #define __FUNCT__ "DMGetPointSF"
3256 /*@
3257   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3258 
3259   Input Parameter:
3260 . dm - The DM
3261 
3262   Output Parameter:
3263 . sf - The PetscSF
3264 
3265   Level: intermediate
3266 
3267   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3268 
3269 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3270 @*/
3271 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3272 {
3273   PetscFunctionBegin;
3274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3275   PetscValidPointer(sf, 2);
3276   *sf = dm->sf;
3277   PetscFunctionReturn(0);
3278 }
3279 
3280 #undef __FUNCT__
3281 #define __FUNCT__ "DMSetPointSF"
3282 /*@
3283   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3284 
3285   Input Parameters:
3286 + dm - The DM
3287 - sf - The PetscSF
3288 
3289   Level: intermediate
3290 
3291 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3292 @*/
3293 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3294 {
3295   PetscErrorCode ierr;
3296 
3297   PetscFunctionBegin;
3298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3299   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3300   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3301   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3302   dm->sf = sf;
3303   PetscFunctionReturn(0);
3304 }
3305 
3306 #undef __FUNCT__
3307 #define __FUNCT__ "DMGetDS"
3308 /*@
3309   DMGetDS - Get the PetscDS
3310 
3311   Input Parameter:
3312 . dm - The DM
3313 
3314   Output Parameter:
3315 . prob - The PetscDS
3316 
3317   Level: developer
3318 
3319 .seealso: DMSetDS()
3320 @*/
3321 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3322 {
3323   PetscFunctionBegin;
3324   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3325   PetscValidPointer(prob, 2);
3326   *prob = dm->prob;
3327   PetscFunctionReturn(0);
3328 }
3329 
3330 #undef __FUNCT__
3331 #define __FUNCT__ "DMSetDS"
3332 /*@
3333   DMSetDS - Set the PetscDS
3334 
3335   Input Parameters:
3336 + dm - The DM
3337 - prob - The PetscDS
3338 
3339   Level: developer
3340 
3341 .seealso: DMGetDS()
3342 @*/
3343 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3344 {
3345   PetscErrorCode ierr;
3346 
3347   PetscFunctionBegin;
3348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3349   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3350   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3351   dm->prob = prob;
3352   ierr = PetscObjectReference((PetscObject) dm->prob);CHKERRQ(ierr);
3353   PetscFunctionReturn(0);
3354 }
3355 
3356 #undef __FUNCT__
3357 #define __FUNCT__ "DMGetNumFields"
3358 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3359 {
3360   PetscErrorCode ierr;
3361 
3362   PetscFunctionBegin;
3363   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3364   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3365   PetscFunctionReturn(0);
3366 }
3367 
3368 #undef __FUNCT__
3369 #define __FUNCT__ "DMSetNumFields"
3370 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3371 {
3372   PetscInt       Nf, f;
3373   PetscErrorCode ierr;
3374 
3375   PetscFunctionBegin;
3376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3377   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3378   for (f = Nf; f < numFields; ++f) {
3379     PetscContainer obj;
3380 
3381     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3382     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3383     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3384   }
3385   PetscFunctionReturn(0);
3386 }
3387 
3388 #undef __FUNCT__
3389 #define __FUNCT__ "DMGetField"
3390 /*@
3391   DMGetField - Return the discretization object for a given DM field
3392 
3393   Not collective
3394 
3395   Input Parameters:
3396 + dm - The DM
3397 - f  - The field number
3398 
3399   Output Parameter:
3400 . field - The discretization object
3401 
3402   Level: developer
3403 
3404 .seealso: DMSetField()
3405 @*/
3406 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3407 {
3408   PetscErrorCode ierr;
3409 
3410   PetscFunctionBegin;
3411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3412   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3413   PetscFunctionReturn(0);
3414 }
3415 
3416 #undef __FUNCT__
3417 #define __FUNCT__ "DMSetField"
3418 /*@
3419   DMSetField - Set the discretization object for a given DM field
3420 
3421   Logically collective on DM
3422 
3423   Input Parameters:
3424 + dm - The DM
3425 . f  - The field number
3426 - field - The discretization object
3427 
3428   Level: developer
3429 
3430 .seealso: DMGetField()
3431 @*/
3432 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3433 {
3434   PetscErrorCode ierr;
3435 
3436   PetscFunctionBegin;
3437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3438   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3439   PetscFunctionReturn(0);
3440 }
3441 
3442 #undef __FUNCT__
3443 #define __FUNCT__ "DMRestrictHook_Coordinates"
3444 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3445 {
3446   DM dm_coord,dmc_coord;
3447   PetscErrorCode ierr;
3448   Vec coords,ccoords;
3449   VecScatter scat;
3450   PetscFunctionBegin;
3451   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3452   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3453   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3454   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3455   if (coords && !ccoords) {
3456     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3457     ierr = DMCreateInjection(dmc_coord,dm_coord,&scat);CHKERRQ(ierr);
3458     ierr = VecScatterBegin(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3459     ierr = VecScatterEnd(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3460     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3461     ierr = VecScatterDestroy(&scat);CHKERRQ(ierr);
3462     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3463   }
3464   PetscFunctionReturn(0);
3465 }
3466 
3467 #undef __FUNCT__
3468 #define __FUNCT__ "DMSubDomainHook_Coordinates"
3469 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3470 {
3471   DM dm_coord,subdm_coord;
3472   PetscErrorCode ierr;
3473   Vec coords,ccoords,clcoords;
3474   VecScatter *scat_i,*scat_g;
3475   PetscFunctionBegin;
3476   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3477   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3478   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3479   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3480   if (coords && !ccoords) {
3481     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3482     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3483     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3484     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3485     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3486     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3487     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3488     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3489     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3490     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3491     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3492     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3493     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3494     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3495     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3496   }
3497   PetscFunctionReturn(0);
3498 }
3499 
3500 #undef __FUNCT__
3501 #define __FUNCT__ "DMGetDimension"
3502 /*@
3503   DMGetDimension - Return the topological dimension of the DM
3504 
3505   Not collective
3506 
3507   Input Parameter:
3508 . dm - The DM
3509 
3510   Output Parameter:
3511 . dim - The topological dimension
3512 
3513   Level: beginner
3514 
3515 .seealso: DMSetDimension(), DMCreate()
3516 @*/
3517 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3518 {
3519   PetscFunctionBegin;
3520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3521   PetscValidPointer(dim, 2);
3522   *dim = dm->dim;
3523   PetscFunctionReturn(0);
3524 }
3525 
3526 #undef __FUNCT__
3527 #define __FUNCT__ "DMSetDimension"
3528 /*@
3529   DMSetDimension - Set the topological dimension of the DM
3530 
3531   Collective on dm
3532 
3533   Input Parameters:
3534 + dm - The DM
3535 - dim - The topological dimension
3536 
3537   Level: beginner
3538 
3539 .seealso: DMGetDimension(), DMCreate()
3540 @*/
3541 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3542 {
3543   PetscFunctionBegin;
3544   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3545   PetscValidLogicalCollectiveInt(dm, dim, 2);
3546   dm->dim = dim;
3547   PetscFunctionReturn(0);
3548 }
3549 
3550 #undef __FUNCT__
3551 #define __FUNCT__ "DMGetDimPoints"
3552 /*@
3553   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3554 
3555   Collective on DM
3556 
3557   Input Parameters:
3558 + dm - the DM
3559 - dim - the dimension
3560 
3561   Output Parameters:
3562 + pStart - The first point of the given dimension
3563 . pEnd - The first point following points of the given dimension
3564 
3565   Note:
3566   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3567   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3568   then the interval is empty.
3569 
3570   Level: intermediate
3571 
3572 .keywords: point, Hasse Diagram, dimension
3573 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3574 @*/
3575 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3576 {
3577   PetscInt       d;
3578   PetscErrorCode ierr;
3579 
3580   PetscFunctionBegin;
3581   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3582   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3583   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3584   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3585   PetscFunctionReturn(0);
3586 }
3587 
3588 #undef __FUNCT__
3589 #define __FUNCT__ "DMSetCoordinates"
3590 /*@
3591   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3592 
3593   Collective on DM
3594 
3595   Input Parameters:
3596 + dm - the DM
3597 - c - coordinate vector
3598 
3599   Note:
3600   The coordinates do include those for ghost points, which are in the local vector
3601 
3602   Level: intermediate
3603 
3604 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3605 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3606 @*/
3607 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3608 {
3609   PetscErrorCode ierr;
3610 
3611   PetscFunctionBegin;
3612   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3613   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3614   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3615   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3616   dm->coordinates = c;
3617   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3618   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3619   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3620   PetscFunctionReturn(0);
3621 }
3622 
3623 #undef __FUNCT__
3624 #define __FUNCT__ "DMSetCoordinatesLocal"
3625 /*@
3626   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3627 
3628   Collective on DM
3629 
3630    Input Parameters:
3631 +  dm - the DM
3632 -  c - coordinate vector
3633 
3634   Note:
3635   The coordinates of ghost points can be set using DMSetCoordinates()
3636   followed by DMGetCoordinatesLocal(). This is intended to enable the
3637   setting of ghost coordinates outside of the domain.
3638 
3639   Level: intermediate
3640 
3641 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3642 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3643 @*/
3644 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3645 {
3646   PetscErrorCode ierr;
3647 
3648   PetscFunctionBegin;
3649   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3650   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3651   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3652   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3653 
3654   dm->coordinatesLocal = c;
3655 
3656   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3657   PetscFunctionReturn(0);
3658 }
3659 
3660 #undef __FUNCT__
3661 #define __FUNCT__ "DMGetCoordinates"
3662 /*@
3663   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
3664 
3665   Not Collective
3666 
3667   Input Parameter:
3668 . dm - the DM
3669 
3670   Output Parameter:
3671 . c - global coordinate vector
3672 
3673   Note:
3674   This is a borrowed reference, so the user should NOT destroy this vector
3675 
3676   Each process has only the local coordinates (does NOT have the ghost coordinates).
3677 
3678   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3679   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3680 
3681   Level: intermediate
3682 
3683 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3684 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
3685 @*/
3686 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
3687 {
3688   PetscErrorCode ierr;
3689 
3690   PetscFunctionBegin;
3691   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3692   PetscValidPointer(c,2);
3693   if (!dm->coordinates && dm->coordinatesLocal) {
3694     DM cdm = NULL;
3695 
3696     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3697     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
3698     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
3699     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3700     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3701   }
3702   *c = dm->coordinates;
3703   PetscFunctionReturn(0);
3704 }
3705 
3706 #undef __FUNCT__
3707 #define __FUNCT__ "DMGetCoordinatesLocal"
3708 /*@
3709   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
3710 
3711   Collective on DM
3712 
3713   Input Parameter:
3714 . dm - the DM
3715 
3716   Output Parameter:
3717 . c - coordinate vector
3718 
3719   Note:
3720   This is a borrowed reference, so the user should NOT destroy this vector
3721 
3722   Each process has the local and ghost coordinates
3723 
3724   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3725   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3726 
3727   Level: intermediate
3728 
3729 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3730 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
3731 @*/
3732 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
3733 {
3734   PetscErrorCode ierr;
3735 
3736   PetscFunctionBegin;
3737   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3738   PetscValidPointer(c,2);
3739   if (!dm->coordinatesLocal && dm->coordinates) {
3740     DM cdm = NULL;
3741 
3742     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3743     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
3744     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
3745     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3746     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3747   }
3748   *c = dm->coordinatesLocal;
3749   PetscFunctionReturn(0);
3750 }
3751 
3752 #undef __FUNCT__
3753 #define __FUNCT__ "DMGetCoordinateDM"
3754 /*@
3755   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
3756 
3757   Collective on DM
3758 
3759   Input Parameter:
3760 . dm - the DM
3761 
3762   Output Parameter:
3763 . cdm - coordinate DM
3764 
3765   Level: intermediate
3766 
3767 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3768 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3769 @*/
3770 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
3771 {
3772   PetscErrorCode ierr;
3773 
3774   PetscFunctionBegin;
3775   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3776   PetscValidPointer(cdm,2);
3777   if (!dm->coordinateDM) {
3778     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
3779     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
3780   }
3781   *cdm = dm->coordinateDM;
3782   PetscFunctionReturn(0);
3783 }
3784 
3785 #undef __FUNCT__
3786 #define __FUNCT__ "DMSetCoordinateDM"
3787 /*@
3788   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
3789 
3790   Logically Collective on DM
3791 
3792   Input Parameters:
3793 + dm - the DM
3794 - cdm - coordinate DM
3795 
3796   Level: intermediate
3797 
3798 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3799 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3800 @*/
3801 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
3802 {
3803   PetscErrorCode ierr;
3804 
3805   PetscFunctionBegin;
3806   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3807   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
3808   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
3809   dm->coordinateDM = cdm;
3810   ierr = PetscObjectReference((PetscObject) dm->coordinateDM);CHKERRQ(ierr);
3811   PetscFunctionReturn(0);
3812 }
3813 
3814 #undef __FUNCT__
3815 #define __FUNCT__ "DMGetCoordinateDim"
3816 /*@
3817   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
3818 
3819   Not Collective
3820 
3821   Input Parameter:
3822 . dm - The DM object
3823 
3824   Output Parameter:
3825 . dim - The embedding dimension
3826 
3827   Level: intermediate
3828 
3829 .keywords: mesh, coordinates
3830 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
3831 @*/
3832 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
3833 {
3834   PetscFunctionBegin;
3835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3836   PetscValidPointer(dim, 2);
3837   if (dm->dimEmbed == PETSC_DEFAULT) {
3838     dm->dimEmbed = dm->dim;
3839   }
3840   *dim = dm->dimEmbed;
3841   PetscFunctionReturn(0);
3842 }
3843 
3844 #undef __FUNCT__
3845 #define __FUNCT__ "DMSetCoordinateDim"
3846 /*@
3847   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
3848 
3849   Not Collective
3850 
3851   Input Parameters:
3852 + dm  - The DM object
3853 - dim - The embedding dimension
3854 
3855   Level: intermediate
3856 
3857 .keywords: mesh, coordinates
3858 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
3859 @*/
3860 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
3861 {
3862   PetscFunctionBegin;
3863   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3864   dm->dimEmbed = dim;
3865   PetscFunctionReturn(0);
3866 }
3867 
3868 #undef __FUNCT__
3869 #define __FUNCT__ "DMGetCoordinateSection"
3870 /*@
3871   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
3872 
3873   Not Collective
3874 
3875   Input Parameter:
3876 . dm - The DM object
3877 
3878   Output Parameter:
3879 . section - The PetscSection object
3880 
3881   Level: intermediate
3882 
3883 .keywords: mesh, coordinates
3884 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
3885 @*/
3886 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
3887 {
3888   DM             cdm;
3889   PetscErrorCode ierr;
3890 
3891   PetscFunctionBegin;
3892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3893   PetscValidPointer(section, 2);
3894   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3895   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
3896   PetscFunctionReturn(0);
3897 }
3898 
3899 #undef __FUNCT__
3900 #define __FUNCT__ "DMSetCoordinateSection"
3901 /*@
3902   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
3903 
3904   Not Collective
3905 
3906   Input Parameters:
3907 + dm      - The DM object
3908 . dim     - The embedding dimension, or PETSC_DETERMINE
3909 - section - The PetscSection object
3910 
3911   Level: intermediate
3912 
3913 .keywords: mesh, coordinates
3914 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
3915 @*/
3916 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
3917 {
3918   DM             cdm;
3919   PetscErrorCode ierr;
3920 
3921   PetscFunctionBegin;
3922   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3923   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
3924   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3925   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
3926   if (dim == PETSC_DETERMINE) {
3927     PetscInt d = dim;
3928     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
3929 
3930     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3931     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3932     pStart = PetscMax(vStart, pStart);
3933     pEnd   = PetscMin(vEnd, pEnd);
3934     for (v = pStart; v < pEnd; ++v) {
3935       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
3936       if (dd) {d = dd; break;}
3937     }
3938     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
3939   }
3940   PetscFunctionReturn(0);
3941 }
3942 
3943 #undef __FUNCT__
3944 #define __FUNCT__ "DMGetPeriodicity"
3945 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L)
3946 {
3947   PetscFunctionBegin;
3948   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3949   if (L)       *L       = dm->L;
3950   if (maxCell) *maxCell = dm->maxCell;
3951   PetscFunctionReturn(0);
3952 }
3953 
3954 #undef __FUNCT__
3955 #define __FUNCT__ "DMSetPeriodicity"
3956 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[])
3957 {
3958   Vec            coordinates;
3959   PetscInt       dim, d;
3960   PetscErrorCode ierr;
3961 
3962   PetscFunctionBegin;
3963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3964   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3965   ierr = VecGetBlockSize(coordinates, &dim);CHKERRQ(ierr);
3966   ierr = PetscMalloc1(dim,&dm->L);CHKERRQ(ierr);
3967   ierr = PetscMalloc1(dim,&dm->maxCell);CHKERRQ(ierr);
3968   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d];}
3969   PetscFunctionReturn(0);
3970 }
3971 
3972 #undef __FUNCT__
3973 #define __FUNCT__ "DMLocatePoints"
3974 /*@
3975   DMLocatePoints - Locate the points in v in the mesh and return an IS of the containing cells
3976 
3977   Not collective
3978 
3979   Input Parameters:
3980 + dm - The DM
3981 - v - The Vec of points
3982 
3983   Output Parameter:
3984 . cells - The local cell numbers for cells which contain the points
3985 
3986   Level: developer
3987 
3988 .keywords: point location, mesh
3989 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3990 @*/
3991 PetscErrorCode DMLocatePoints(DM dm, Vec v, IS *cells)
3992 {
3993   PetscErrorCode ierr;
3994 
3995   PetscFunctionBegin;
3996   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3997   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
3998   PetscValidPointer(cells,3);
3999   if (dm->ops->locatepoints) {
4000     ierr = (*dm->ops->locatepoints)(dm,v,cells);CHKERRQ(ierr);
4001   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4002   PetscFunctionReturn(0);
4003 }
4004 
4005 #undef __FUNCT__
4006 #define __FUNCT__ "DMGetOutputDM"
4007 /*@
4008   DMGetOutputDM - Retrieve the DM associated with the layout for output
4009 
4010   Input Parameter:
4011 . dm - The original DM
4012 
4013   Output Parameter:
4014 . odm - The DM which provides the layout for output
4015 
4016   Level: intermediate
4017 
4018 .seealso: VecView(), DMGetDefaultGlobalSection()
4019 @*/
4020 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4021 {
4022   PetscSection   section;
4023   PetscBool      hasConstraints;
4024   PetscErrorCode ierr;
4025 
4026   PetscFunctionBegin;
4027   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4028   PetscValidPointer(odm,2);
4029   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4030   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4031   if (!hasConstraints) {
4032     *odm = dm;
4033     PetscFunctionReturn(0);
4034   }
4035   if (!dm->dmBC) {
4036     PetscSection newSection, gsection;
4037     PetscSF      sf;
4038 
4039     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4040     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4041     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4042     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4043     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4044     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, &gsection);CHKERRQ(ierr);
4045     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4046     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4047   }
4048   *odm = dm->dmBC;
4049   PetscFunctionReturn(0);
4050 }
4051 
4052 #undef __FUNCT__
4053 #define __FUNCT__ "DMGetOutputSequenceNumber"
4054 /*@
4055   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4056 
4057   Input Parameter:
4058 . dm - The original DM
4059 
4060   Output Parameters:
4061 + num - The output sequence number
4062 - val - The output sequence value
4063 
4064   Level: intermediate
4065 
4066   Note: This is intended for output that should appear in sequence, for instance
4067   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4068 
4069 .seealso: VecView()
4070 @*/
4071 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4072 {
4073   PetscFunctionBegin;
4074   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4075   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4076   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4077   PetscFunctionReturn(0);
4078 }
4079 
4080 #undef __FUNCT__
4081 #define __FUNCT__ "DMSetOutputSequenceNumber"
4082 /*@
4083   DMSetOutputSequenceNumber - Set the sequence number/value for output
4084 
4085   Input Parameters:
4086 + dm - The original DM
4087 . num - The output sequence number
4088 - val - The output sequence value
4089 
4090   Level: intermediate
4091 
4092   Note: This is intended for output that should appear in sequence, for instance
4093   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4094 
4095 .seealso: VecView()
4096 @*/
4097 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4098 {
4099   PetscFunctionBegin;
4100   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4101   dm->outputSequenceNum = num;
4102   dm->outputSequenceVal = val;
4103   PetscFunctionReturn(0);
4104 }
4105 
4106 #undef __FUNCT__
4107 #define __FUNCT__ "DMOutputSequenceLoad"
4108 /*@C
4109   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4110 
4111   Input Parameters:
4112 + dm   - The original DM
4113 . name - The sequence name
4114 - num  - The output sequence number
4115 
4116   Output Parameter:
4117 . val  - The output sequence value
4118 
4119   Level: intermediate
4120 
4121   Note: This is intended for output that should appear in sequence, for instance
4122   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4123 
4124 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4125 @*/
4126 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4127 {
4128   PetscBool      ishdf5;
4129   PetscErrorCode ierr;
4130 
4131   PetscFunctionBegin;
4132   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4133   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4134   PetscValidPointer(val,4);
4135   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4136   if (ishdf5) {
4137 #if defined(PETSC_HAVE_HDF5)
4138     PetscScalar value;
4139 
4140     ierr = DMSequenceLoad_HDF5(dm, name, num, &value, viewer);CHKERRQ(ierr);
4141     *val = PetscRealPart(value);
4142 #endif
4143   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4144   PetscFunctionReturn(0);
4145 }
4146