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