xref: /petsc/src/dm/interface/dm.c (revision c783eb9e7d4443df2d00ad8bb41dd887df99e093)
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         dsize;
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,&dsize);CHKERRQ(ierr);
1007   if (dsize*count > link->bytes) {
1008     ierr        = PetscFree(link->mem);CHKERRQ(ierr);
1009     ierr        = PetscMalloc(dsize*count,&link->mem);CHKERRQ(ierr);
1010     link->bytes = dsize*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__ "DMGlobalToLocalHook_Constraints"
1623 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
1624 {
1625   Mat cMat;
1626   Vec cVec;
1627   PetscSection section, cSec;
1628   PetscInt pStart, pEnd, p, dof;
1629   PetscErrorCode ierr;
1630 
1631   PetscFunctionBegin;
1632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1633   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
1634   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
1635     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
1636     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
1637     ierr = MatMult(cMat,l,cVec);CHKERRQ(ierr);
1638     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
1639     for (p = pStart; p < pEnd; p++) {
1640       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
1641       if (dof) {
1642         PetscScalar *vals;
1643         ierr = VecGetValuesSection(cVec,cSec,p,&vals);CHKERRQ(ierr);
1644         ierr = VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);CHKERRQ(ierr);
1645       }
1646     }
1647     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
1648   }
1649   PetscFunctionReturn(0);
1650 }
1651 
1652 #undef __FUNCT__
1653 #define __FUNCT__ "DMGlobalToLocalBegin"
1654 /*@
1655     DMGlobalToLocalBegin - Begins updating local vectors from global vector
1656 
1657     Neighbor-wise Collective on DM
1658 
1659     Input Parameters:
1660 +   dm - the DM object
1661 .   g - the global vector
1662 .   mode - INSERT_VALUES or ADD_VALUES
1663 -   l - the local vector
1664 
1665 
1666     Level: beginner
1667 
1668 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1669 
1670 @*/
1671 PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1672 {
1673   PetscSF                 sf;
1674   PetscErrorCode          ierr;
1675   DMGlobalToLocalHookLink link;
1676 
1677   PetscFunctionBegin;
1678   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1679   for (link=dm->gtolhook; link; link=link->next) {
1680     if (link->beginhook) {
1681       ierr = (*link->beginhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);
1682     }
1683   }
1684   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1685   if (sf) {
1686     PetscScalar *lArray, *gArray;
1687 
1688     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1689     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1690     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1691     ierr = PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1692     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1693     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1694   } else {
1695     ierr = (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1696   }
1697   PetscFunctionReturn(0);
1698 }
1699 
1700 #undef __FUNCT__
1701 #define __FUNCT__ "DMGlobalToLocalEnd"
1702 /*@
1703     DMGlobalToLocalEnd - Ends updating local vectors from global vector
1704 
1705     Neighbor-wise Collective on DM
1706 
1707     Input Parameters:
1708 +   dm - the DM object
1709 .   g - the global vector
1710 .   mode - INSERT_VALUES or ADD_VALUES
1711 -   l - the local vector
1712 
1713 
1714     Level: beginner
1715 
1716 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1717 
1718 @*/
1719 PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1720 {
1721   PetscSF                 sf;
1722   PetscErrorCode          ierr;
1723   PetscScalar             *lArray, *gArray;
1724   DMGlobalToLocalHookLink link;
1725 
1726   PetscFunctionBegin;
1727   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1728   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1729   if (sf) {
1730     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1731 
1732     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1733     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1734     ierr = PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1735     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1736     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1737   } else {
1738     ierr = (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1739   }
1740   ierr = DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);CHKERRQ(ierr);
1741   for (link=dm->gtolhook; link; link=link->next) {
1742     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1743   }
1744   PetscFunctionReturn(0);
1745 }
1746 
1747 #undef __FUNCT__
1748 #define __FUNCT__ "DMLocalToGlobalHookAdd"
1749 /*@C
1750    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
1751 
1752    Logically Collective
1753 
1754    Input Arguments:
1755 +  dm - the DM
1756 .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
1757 .  endhook - function to run after DMLocalToGlobalEnd() has completed
1758 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1759 
1760    Calling sequence for beginhook:
1761 $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1762 
1763 +  dm - global DM
1764 .  l - local vector
1765 .  mode - mode
1766 .  g - global vector
1767 -  ctx - optional user-defined function context
1768 
1769 
1770    Calling sequence for endhook:
1771 $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1772 
1773 +  global - global DM
1774 .  l - local vector
1775 .  mode - mode
1776 .  g - global vector
1777 -  ctx - optional user-defined function context
1778 
1779    Level: advanced
1780 
1781 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1782 @*/
1783 PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1784 {
1785   PetscErrorCode          ierr;
1786   DMLocalToGlobalHookLink link,*p;
1787 
1788   PetscFunctionBegin;
1789   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1790   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1791   ierr            = PetscMalloc(sizeof(struct _DMLocalToGlobalHookLink),&link);CHKERRQ(ierr);
1792   link->beginhook = beginhook;
1793   link->endhook   = endhook;
1794   link->ctx       = ctx;
1795   link->next      = NULL;
1796   *p              = link;
1797   PetscFunctionReturn(0);
1798 }
1799 
1800 #undef __FUNCT__
1801 #define __FUNCT__ "DMLocalToGlobalHook_Constraints"
1802 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
1803 {
1804   Mat cMat;
1805   Vec cVec;
1806   PetscSection section, cSec;
1807   PetscInt pStart, pEnd, p, dof;
1808   PetscErrorCode ierr;
1809 
1810   PetscFunctionBegin;
1811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1812   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
1813   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
1814     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
1815     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
1816     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
1817     for (p = pStart; p < pEnd; p++) {
1818       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
1819       if (dof) {
1820         PetscInt d;
1821         PetscScalar *vals;
1822         ierr = VecGetValuesSection(l,section,p,&vals);CHKERRQ(ierr);
1823         ierr = VecSetValuesSection(cVec,cSec,p,vals,mode);CHKERRQ(ierr);
1824         /* for this to be the true transpose, we have to zero the values that
1825          * we just extracted */
1826         for (d = 0; d < dof; d++) {
1827           vals[d] = 0.;
1828         }
1829       }
1830     }
1831     ierr = MatMultTransposeAdd(cMat,cVec,l,l);CHKERRQ(ierr);
1832     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
1833   }
1834   PetscFunctionReturn(0);
1835 }
1836 
1837 #undef __FUNCT__
1838 #define __FUNCT__ "DMLocalToGlobalBegin"
1839 /*@
1840     DMLocalToGlobalBegin - updates global vectors from local vectors
1841 
1842     Neighbor-wise Collective on DM
1843 
1844     Input Parameters:
1845 +   dm - the DM object
1846 .   l - the local vector
1847 .   mode - if INSERT_VALUES then no parallel communication is used, if ADD_VALUES then all ghost points from the same base point accumulate into that base point.
1848 -   g - the global vector
1849 
1850     Notes: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
1851            INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
1852 
1853     Level: beginner
1854 
1855 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
1856 
1857 @*/
1858 PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
1859 {
1860   PetscSF                 sf;
1861   PetscSection            s, gs;
1862   DMLocalToGlobalHookLink link;
1863   PetscScalar            *lArray, *gArray;
1864   PetscBool               isInsert;
1865   PetscErrorCode          ierr;
1866 
1867   PetscFunctionBegin;
1868   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1869   for (link=dm->ltoghook; link; link=link->next) {
1870     if (link->beginhook) {
1871       ierr = (*link->beginhook)(dm,l,mode,g,link->ctx);CHKERRQ(ierr);
1872     }
1873   }
1874   ierr = DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);CHKERRQ(ierr);
1875   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1876   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
1877   switch (mode) {
1878   case INSERT_VALUES:
1879   case INSERT_ALL_VALUES:
1880     isInsert = PETSC_TRUE; break;
1881   case ADD_VALUES:
1882   case ADD_ALL_VALUES:
1883     isInsert = PETSC_FALSE; break;
1884   default:
1885     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1886   }
1887   if (sf && !isInsert) {
1888     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1889     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1890     ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPI_SUM);CHKERRQ(ierr);
1891     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1892     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1893   } else if (s && isInsert) {
1894     PetscInt gStart, pStart, pEnd, p;
1895 
1896     ierr = DMGetDefaultGlobalSection(dm, &gs);CHKERRQ(ierr);
1897     ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1898     ierr = VecGetOwnershipRange(g, &gStart, NULL);CHKERRQ(ierr);
1899     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1900     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1901     for (p = pStart; p < pEnd; ++p) {
1902       PetscInt dof, cdof, off, goff, d, g;
1903 
1904       ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
1905       ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
1906       ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
1907       ierr = PetscSectionGetOffset(gs, p, &goff);CHKERRQ(ierr);
1908       if (goff < 0) continue;
1909       if (!cdof) {
1910         for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
1911       } else {
1912         const PetscInt *cdofs;
1913         PetscInt        cind = 0;
1914 
1915         ierr = PetscSectionGetConstraintIndices(s, p, &cdofs);CHKERRQ(ierr);
1916         for (d = 0, g = 0; d < dof; ++d) {
1917           if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
1918           gArray[goff-gStart+g++] = lArray[off+d];
1919         }
1920       }
1921     }
1922     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1923     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1924   } else {
1925     ierr = (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1926   }
1927   PetscFunctionReturn(0);
1928 }
1929 
1930 #undef __FUNCT__
1931 #define __FUNCT__ "DMLocalToGlobalEnd"
1932 /*@
1933     DMLocalToGlobalEnd - updates global vectors from local vectors
1934 
1935     Neighbor-wise Collective on DM
1936 
1937     Input Parameters:
1938 +   dm - the DM object
1939 .   l - the local vector
1940 .   mode - INSERT_VALUES or ADD_VALUES
1941 -   g - the global vector
1942 
1943 
1944     Level: beginner
1945 
1946 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
1947 
1948 @*/
1949 PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
1950 {
1951   PetscSF                 sf;
1952   PetscSection            s;
1953   DMLocalToGlobalHookLink link;
1954   PetscBool               isInsert;
1955   PetscErrorCode          ierr;
1956 
1957   PetscFunctionBegin;
1958   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1959   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1960   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
1961   switch (mode) {
1962   case INSERT_VALUES:
1963   case INSERT_ALL_VALUES:
1964     isInsert = PETSC_TRUE; break;
1965   case ADD_VALUES:
1966   case ADD_ALL_VALUES:
1967     isInsert = PETSC_FALSE; break;
1968   default:
1969     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1970   }
1971   if (sf && !isInsert) {
1972     PetscScalar *lArray, *gArray;
1973 
1974     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1975     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1976     ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPI_SUM);CHKERRQ(ierr);
1977     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1978     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1979   } else if (s && isInsert) {
1980   } else {
1981     ierr = (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1982   }
1983   for (link=dm->ltoghook; link; link=link->next) {
1984     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1985   }
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 #undef __FUNCT__
1990 #define __FUNCT__ "DMLocalToLocalBegin"
1991 /*@
1992    DMLocalToLocalBegin - Maps from a local vector (including ghost points
1993    that contain irrelevant values) to another local vector where the ghost
1994    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
1995 
1996    Neighbor-wise Collective on DM and Vec
1997 
1998    Input Parameters:
1999 +  dm - the DM object
2000 .  g - the original local vector
2001 -  mode - one of INSERT_VALUES or ADD_VALUES
2002 
2003    Output Parameter:
2004 .  l  - the local vector with correct ghost values
2005 
2006    Level: intermediate
2007 
2008    Notes:
2009    The local vectors used here need not be the same as those
2010    obtained from DMCreateLocalVector(), BUT they
2011    must have the same parallel data layout; they could, for example, be
2012    obtained with VecDuplicate() from the DM originating vectors.
2013 
2014 .keywords: DM, local-to-local, begin
2015 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2016 
2017 @*/
2018 PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2019 {
2020   PetscErrorCode          ierr;
2021 
2022   PetscFunctionBegin;
2023   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2024   ierr = (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2025   PetscFunctionReturn(0);
2026 }
2027 
2028 #undef __FUNCT__
2029 #define __FUNCT__ "DMLocalToLocalEnd"
2030 /*@
2031    DMLocalToLocalEnd - Maps from a local vector (including ghost points
2032    that contain irrelevant values) to another local vector where the ghost
2033    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2034 
2035    Neighbor-wise Collective on DM and Vec
2036 
2037    Input Parameters:
2038 +  da - the DM object
2039 .  g - the original local vector
2040 -  mode - one of INSERT_VALUES or ADD_VALUES
2041 
2042    Output Parameter:
2043 .  l  - the local vector with correct ghost values
2044 
2045    Level: intermediate
2046 
2047    Notes:
2048    The local vectors used here need not be the same as those
2049    obtained from DMCreateLocalVector(), BUT they
2050    must have the same parallel data layout; they could, for example, be
2051    obtained with VecDuplicate() from the DM originating vectors.
2052 
2053 .keywords: DM, local-to-local, end
2054 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2055 
2056 @*/
2057 PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2058 {
2059   PetscErrorCode          ierr;
2060 
2061   PetscFunctionBegin;
2062   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2063   ierr = (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2064   PetscFunctionReturn(0);
2065 }
2066 
2067 
2068 #undef __FUNCT__
2069 #define __FUNCT__ "DMCoarsen"
2070 /*@
2071     DMCoarsen - Coarsens a DM object
2072 
2073     Collective on DM
2074 
2075     Input Parameter:
2076 +   dm - the DM object
2077 -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2078 
2079     Output Parameter:
2080 .   dmc - the coarsened DM
2081 
2082     Level: developer
2083 
2084 .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2085 
2086 @*/
2087 PetscErrorCode  DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2088 {
2089   PetscErrorCode    ierr;
2090   DMCoarsenHookLink link;
2091 
2092   PetscFunctionBegin;
2093   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2094   ierr                      = (*dm->ops->coarsen)(dm, comm, dmc);CHKERRQ(ierr);
2095   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2096   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
2097   (*dmc)->ctx               = dm->ctx;
2098   (*dmc)->levelup           = dm->levelup;
2099   (*dmc)->leveldown         = dm->leveldown + 1;
2100   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
2101   for (link=dm->coarsenhook; link; link=link->next) {
2102     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
2103   }
2104   PetscFunctionReturn(0);
2105 }
2106 
2107 #undef __FUNCT__
2108 #define __FUNCT__ "DMCoarsenHookAdd"
2109 /*@C
2110    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2111 
2112    Logically Collective
2113 
2114    Input Arguments:
2115 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2116 .  coarsenhook - function to run when setting up a coarser level
2117 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2118 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2119 
2120    Calling sequence of coarsenhook:
2121 $    coarsenhook(DM fine,DM coarse,void *ctx);
2122 
2123 +  fine - fine level DM
2124 .  coarse - coarse level DM to restrict problem to
2125 -  ctx - optional user-defined function context
2126 
2127    Calling sequence for restricthook:
2128 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2129 
2130 +  fine - fine level DM
2131 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2132 .  rscale - scaling vector for restriction
2133 .  inject - matrix restricting by injection
2134 .  coarse - coarse level DM to update
2135 -  ctx - optional user-defined function context
2136 
2137    Level: advanced
2138 
2139    Notes:
2140    This function is only needed if auxiliary data needs to be set up on coarse grids.
2141 
2142    If this function is called multiple times, the hooks will be run in the order they are added.
2143 
2144    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2145    extract the finest level information from its context (instead of from the SNES).
2146 
2147    This function is currently not available from Fortran.
2148 
2149 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2150 @*/
2151 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2152 {
2153   PetscErrorCode    ierr;
2154   DMCoarsenHookLink link,*p;
2155 
2156   PetscFunctionBegin;
2157   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2158   for (p=&fine->coarsenhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2159   ierr               = PetscMalloc(sizeof(struct _DMCoarsenHookLink),&link);CHKERRQ(ierr);
2160   link->coarsenhook  = coarsenhook;
2161   link->restricthook = restricthook;
2162   link->ctx          = ctx;
2163   link->next         = NULL;
2164   *p                 = link;
2165   PetscFunctionReturn(0);
2166 }
2167 
2168 #undef __FUNCT__
2169 #define __FUNCT__ "DMRestrict"
2170 /*@
2171    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2172 
2173    Collective if any hooks are
2174 
2175    Input Arguments:
2176 +  fine - finer DM to use as a base
2177 .  restrct - restriction matrix, apply using MatRestrict()
2178 .  inject - injection matrix, also use MatRestrict()
2179 -  coarse - coarer DM to update
2180 
2181    Level: developer
2182 
2183 .seealso: DMCoarsenHookAdd(), MatRestrict()
2184 @*/
2185 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2186 {
2187   PetscErrorCode    ierr;
2188   DMCoarsenHookLink link;
2189 
2190   PetscFunctionBegin;
2191   for (link=fine->coarsenhook; link; link=link->next) {
2192     if (link->restricthook) {
2193       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2194     }
2195   }
2196   PetscFunctionReturn(0);
2197 }
2198 
2199 #undef __FUNCT__
2200 #define __FUNCT__ "DMSubDomainHookAdd"
2201 /*@C
2202    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2203 
2204    Logically Collective
2205 
2206    Input Arguments:
2207 +  global - global DM
2208 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2209 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2210 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2211 
2212 
2213    Calling sequence for ddhook:
2214 $    ddhook(DM global,DM block,void *ctx)
2215 
2216 +  global - global DM
2217 .  block  - block DM
2218 -  ctx - optional user-defined function context
2219 
2220    Calling sequence for restricthook:
2221 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2222 
2223 +  global - global DM
2224 .  out    - scatter to the outer (with ghost and overlap points) block vector
2225 .  in     - scatter to block vector values only owned locally
2226 .  block  - block DM
2227 -  ctx - optional user-defined function context
2228 
2229    Level: advanced
2230 
2231    Notes:
2232    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2233 
2234    If this function is called multiple times, the hooks will be run in the order they are added.
2235 
2236    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2237    extract the global information from its context (instead of from the SNES).
2238 
2239    This function is currently not available from Fortran.
2240 
2241 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2242 @*/
2243 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2244 {
2245   PetscErrorCode      ierr;
2246   DMSubDomainHookLink link,*p;
2247 
2248   PetscFunctionBegin;
2249   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2250   for (p=&global->subdomainhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2251   ierr               = PetscMalloc(sizeof(struct _DMSubDomainHookLink),&link);CHKERRQ(ierr);
2252   link->restricthook = restricthook;
2253   link->ddhook       = ddhook;
2254   link->ctx          = ctx;
2255   link->next         = NULL;
2256   *p                 = link;
2257   PetscFunctionReturn(0);
2258 }
2259 
2260 #undef __FUNCT__
2261 #define __FUNCT__ "DMSubDomainRestrict"
2262 /*@
2263    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2264 
2265    Collective if any hooks are
2266 
2267    Input Arguments:
2268 +  fine - finer DM to use as a base
2269 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2270 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2271 -  coarse - coarer DM to update
2272 
2273    Level: developer
2274 
2275 .seealso: DMCoarsenHookAdd(), MatRestrict()
2276 @*/
2277 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2278 {
2279   PetscErrorCode      ierr;
2280   DMSubDomainHookLink link;
2281 
2282   PetscFunctionBegin;
2283   for (link=global->subdomainhook; link; link=link->next) {
2284     if (link->restricthook) {
2285       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2286     }
2287   }
2288   PetscFunctionReturn(0);
2289 }
2290 
2291 #undef __FUNCT__
2292 #define __FUNCT__ "DMGetCoarsenLevel"
2293 /*@
2294     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2295 
2296     Not Collective
2297 
2298     Input Parameter:
2299 .   dm - the DM object
2300 
2301     Output Parameter:
2302 .   level - number of coarsenings
2303 
2304     Level: developer
2305 
2306 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2307 
2308 @*/
2309 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2310 {
2311   PetscFunctionBegin;
2312   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2313   *level = dm->leveldown;
2314   PetscFunctionReturn(0);
2315 }
2316 
2317 
2318 
2319 #undef __FUNCT__
2320 #define __FUNCT__ "DMRefineHierarchy"
2321 /*@C
2322     DMRefineHierarchy - Refines a DM object, all levels at once
2323 
2324     Collective on DM
2325 
2326     Input Parameter:
2327 +   dm - the DM object
2328 -   nlevels - the number of levels of refinement
2329 
2330     Output Parameter:
2331 .   dmf - the refined DM hierarchy
2332 
2333     Level: developer
2334 
2335 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2336 
2337 @*/
2338 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2339 {
2340   PetscErrorCode ierr;
2341 
2342   PetscFunctionBegin;
2343   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2344   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2345   if (nlevels == 0) PetscFunctionReturn(0);
2346   if (dm->ops->refinehierarchy) {
2347     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2348   } else if (dm->ops->refine) {
2349     PetscInt i;
2350 
2351     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2352     for (i=1; i<nlevels; i++) {
2353       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2354     }
2355   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2356   PetscFunctionReturn(0);
2357 }
2358 
2359 #undef __FUNCT__
2360 #define __FUNCT__ "DMCoarsenHierarchy"
2361 /*@C
2362     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2363 
2364     Collective on DM
2365 
2366     Input Parameter:
2367 +   dm - the DM object
2368 -   nlevels - the number of levels of coarsening
2369 
2370     Output Parameter:
2371 .   dmc - the coarsened DM hierarchy
2372 
2373     Level: developer
2374 
2375 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2376 
2377 @*/
2378 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2379 {
2380   PetscErrorCode ierr;
2381 
2382   PetscFunctionBegin;
2383   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2384   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2385   if (nlevels == 0) PetscFunctionReturn(0);
2386   PetscValidPointer(dmc,3);
2387   if (dm->ops->coarsenhierarchy) {
2388     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2389   } else if (dm->ops->coarsen) {
2390     PetscInt i;
2391 
2392     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2393     for (i=1; i<nlevels; i++) {
2394       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2395     }
2396   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2397   PetscFunctionReturn(0);
2398 }
2399 
2400 #undef __FUNCT__
2401 #define __FUNCT__ "DMCreateAggregates"
2402 /*@
2403    DMCreateAggregates - Gets the aggregates that map between
2404    grids associated with two DMs.
2405 
2406    Collective on DM
2407 
2408    Input Parameters:
2409 +  dmc - the coarse grid DM
2410 -  dmf - the fine grid DM
2411 
2412    Output Parameters:
2413 .  rest - the restriction matrix (transpose of the projection matrix)
2414 
2415    Level: intermediate
2416 
2417 .keywords: interpolation, restriction, multigrid
2418 
2419 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2420 @*/
2421 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2422 {
2423   PetscErrorCode ierr;
2424 
2425   PetscFunctionBegin;
2426   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2427   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2428   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2429   PetscFunctionReturn(0);
2430 }
2431 
2432 #undef __FUNCT__
2433 #define __FUNCT__ "DMSetApplicationContextDestroy"
2434 /*@C
2435     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2436 
2437     Not Collective
2438 
2439     Input Parameters:
2440 +   dm - the DM object
2441 -   destroy - the destroy function
2442 
2443     Level: intermediate
2444 
2445 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2446 
2447 @*/
2448 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2449 {
2450   PetscFunctionBegin;
2451   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2452   dm->ctxdestroy = destroy;
2453   PetscFunctionReturn(0);
2454 }
2455 
2456 #undef __FUNCT__
2457 #define __FUNCT__ "DMSetApplicationContext"
2458 /*@
2459     DMSetApplicationContext - Set a user context into a DM object
2460 
2461     Not Collective
2462 
2463     Input Parameters:
2464 +   dm - the DM object
2465 -   ctx - the user context
2466 
2467     Level: intermediate
2468 
2469 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2470 
2471 @*/
2472 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2473 {
2474   PetscFunctionBegin;
2475   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2476   dm->ctx = ctx;
2477   PetscFunctionReturn(0);
2478 }
2479 
2480 #undef __FUNCT__
2481 #define __FUNCT__ "DMGetApplicationContext"
2482 /*@
2483     DMGetApplicationContext - Gets a user context from a DM object
2484 
2485     Not Collective
2486 
2487     Input Parameter:
2488 .   dm - the DM object
2489 
2490     Output Parameter:
2491 .   ctx - the user context
2492 
2493     Level: intermediate
2494 
2495 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2496 
2497 @*/
2498 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2499 {
2500   PetscFunctionBegin;
2501   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2502   *(void**)ctx = dm->ctx;
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 #undef __FUNCT__
2507 #define __FUNCT__ "DMSetVariableBounds"
2508 /*@C
2509     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2510 
2511     Logically Collective on DM
2512 
2513     Input Parameter:
2514 +   dm - the DM object
2515 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
2516 
2517     Level: intermediate
2518 
2519 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2520          DMSetJacobian()
2521 
2522 @*/
2523 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2524 {
2525   PetscFunctionBegin;
2526   dm->ops->computevariablebounds = f;
2527   PetscFunctionReturn(0);
2528 }
2529 
2530 #undef __FUNCT__
2531 #define __FUNCT__ "DMHasVariableBounds"
2532 /*@
2533     DMHasVariableBounds - does the DM object have a variable bounds function?
2534 
2535     Not Collective
2536 
2537     Input Parameter:
2538 .   dm - the DM object to destroy
2539 
2540     Output Parameter:
2541 .   flg - PETSC_TRUE if the variable bounds function exists
2542 
2543     Level: developer
2544 
2545 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2546 
2547 @*/
2548 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2549 {
2550   PetscFunctionBegin;
2551   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2552   PetscFunctionReturn(0);
2553 }
2554 
2555 #undef __FUNCT__
2556 #define __FUNCT__ "DMComputeVariableBounds"
2557 /*@C
2558     DMComputeVariableBounds - compute variable bounds used by SNESVI.
2559 
2560     Logically Collective on DM
2561 
2562     Input Parameters:
2563 +   dm - the DM object to destroy
2564 -   x  - current solution at which the bounds are computed
2565 
2566     Output parameters:
2567 +   xl - lower bound
2568 -   xu - upper bound
2569 
2570     Level: intermediate
2571 
2572 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2573 
2574 @*/
2575 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2576 {
2577   PetscErrorCode ierr;
2578 
2579   PetscFunctionBegin;
2580   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2581   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
2582   if (dm->ops->computevariablebounds) {
2583     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
2584   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2585   PetscFunctionReturn(0);
2586 }
2587 
2588 #undef __FUNCT__
2589 #define __FUNCT__ "DMHasColoring"
2590 /*@
2591     DMHasColoring - does the DM object have a method of providing a coloring?
2592 
2593     Not Collective
2594 
2595     Input Parameter:
2596 .   dm - the DM object
2597 
2598     Output Parameter:
2599 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
2600 
2601     Level: developer
2602 
2603 .seealso DMHasFunction(), DMCreateColoring()
2604 
2605 @*/
2606 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2607 {
2608   PetscFunctionBegin;
2609   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2610   PetscFunctionReturn(0);
2611 }
2612 
2613 #undef  __FUNCT__
2614 #define __FUNCT__ "DMSetVec"
2615 /*@C
2616     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
2617 
2618     Collective on DM
2619 
2620     Input Parameter:
2621 +   dm - the DM object
2622 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
2623 
2624     Level: developer
2625 
2626 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2627 
2628 @*/
2629 PetscErrorCode  DMSetVec(DM dm,Vec x)
2630 {
2631   PetscErrorCode ierr;
2632 
2633   PetscFunctionBegin;
2634   if (x) {
2635     if (!dm->x) {
2636       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
2637     }
2638     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
2639   } else if (dm->x) {
2640     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
2641   }
2642   PetscFunctionReturn(0);
2643 }
2644 
2645 PetscFunctionList DMList              = NULL;
2646 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
2647 
2648 #undef __FUNCT__
2649 #define __FUNCT__ "DMSetType"
2650 /*@C
2651   DMSetType - Builds a DM, for a particular DM implementation.
2652 
2653   Collective on DM
2654 
2655   Input Parameters:
2656 + dm     - The DM object
2657 - method - The name of the DM type
2658 
2659   Options Database Key:
2660 . -dm_type <type> - Sets the DM type; use -help for a list of available types
2661 
2662   Notes:
2663   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
2664 
2665   Level: intermediate
2666 
2667 .keywords: DM, set, type
2668 .seealso: DMGetType(), DMCreate()
2669 @*/
2670 PetscErrorCode  DMSetType(DM dm, DMType method)
2671 {
2672   PetscErrorCode (*r)(DM);
2673   PetscBool      match;
2674   PetscErrorCode ierr;
2675 
2676   PetscFunctionBegin;
2677   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2678   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
2679   if (match) PetscFunctionReturn(0);
2680 
2681   if (!DMRegisterAllCalled) {ierr = DMRegisterAll();CHKERRQ(ierr);}
2682   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
2683   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
2684 
2685   if (dm->ops->destroy) {
2686     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
2687     dm->ops->destroy = NULL;
2688   }
2689   ierr = (*r)(dm);CHKERRQ(ierr);
2690   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
2691   PetscFunctionReturn(0);
2692 }
2693 
2694 #undef __FUNCT__
2695 #define __FUNCT__ "DMGetType"
2696 /*@C
2697   DMGetType - Gets the DM type name (as a string) from the DM.
2698 
2699   Not Collective
2700 
2701   Input Parameter:
2702 . dm  - The DM
2703 
2704   Output Parameter:
2705 . type - The DM type name
2706 
2707   Level: intermediate
2708 
2709 .keywords: DM, get, type, name
2710 .seealso: DMSetType(), DMCreate()
2711 @*/
2712 PetscErrorCode  DMGetType(DM dm, DMType *type)
2713 {
2714   PetscErrorCode ierr;
2715 
2716   PetscFunctionBegin;
2717   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2718   PetscValidPointer(type,2);
2719   if (!DMRegisterAllCalled) {
2720     ierr = DMRegisterAll();CHKERRQ(ierr);
2721   }
2722   *type = ((PetscObject)dm)->type_name;
2723   PetscFunctionReturn(0);
2724 }
2725 
2726 #undef __FUNCT__
2727 #define __FUNCT__ "DMConvert"
2728 /*@C
2729   DMConvert - Converts a DM to another DM, either of the same or different type.
2730 
2731   Collective on DM
2732 
2733   Input Parameters:
2734 + dm - the DM
2735 - newtype - new DM type (use "same" for the same type)
2736 
2737   Output Parameter:
2738 . M - pointer to new DM
2739 
2740   Notes:
2741   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
2742   the MPI communicator of the generated DM is always the same as the communicator
2743   of the input DM.
2744 
2745   Level: intermediate
2746 
2747 .seealso: DMCreate()
2748 @*/
2749 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
2750 {
2751   DM             B;
2752   char           convname[256];
2753   PetscBool      sametype, issame;
2754   PetscErrorCode ierr;
2755 
2756   PetscFunctionBegin;
2757   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2758   PetscValidType(dm,1);
2759   PetscValidPointer(M,3);
2760   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
2761   ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr);
2762   {
2763     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
2764 
2765     /*
2766        Order of precedence:
2767        1) See if a specialized converter is known to the current DM.
2768        2) See if a specialized converter is known to the desired DM class.
2769        3) See if a good general converter is registered for the desired class
2770        4) See if a good general converter is known for the current matrix.
2771        5) Use a really basic converter.
2772     */
2773 
2774     /* 1) See if a specialized converter is known to the current DM and the desired class */
2775     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2776     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2777     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2778     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2779     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2780     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
2781     if (conv) goto foundconv;
2782 
2783     /* 2)  See if a specialized converter is known to the desired DM class. */
2784     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
2785     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
2786     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2787     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2788     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2789     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2790     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2791     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
2792     if (conv) {
2793       ierr = DMDestroy(&B);CHKERRQ(ierr);
2794       goto foundconv;
2795     }
2796 
2797 #if 0
2798     /* 3) See if a good general converter is registered for the desired class */
2799     conv = B->ops->convertfrom;
2800     ierr = DMDestroy(&B);CHKERRQ(ierr);
2801     if (conv) goto foundconv;
2802 
2803     /* 4) See if a good general converter is known for the current matrix */
2804     if (dm->ops->convert) {
2805       conv = dm->ops->convert;
2806     }
2807     if (conv) goto foundconv;
2808 #endif
2809 
2810     /* 5) Use a really basic converter. */
2811     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
2812 
2813 foundconv:
2814     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2815     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
2816     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2817   }
2818   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
2819   PetscFunctionReturn(0);
2820 }
2821 
2822 /*--------------------------------------------------------------------------------------------------------------------*/
2823 
2824 #undef __FUNCT__
2825 #define __FUNCT__ "DMRegister"
2826 /*@C
2827   DMRegister -  Adds a new DM component implementation
2828 
2829   Not Collective
2830 
2831   Input Parameters:
2832 + name        - The name of a new user-defined creation routine
2833 - create_func - The creation routine itself
2834 
2835   Notes:
2836   DMRegister() may be called multiple times to add several user-defined DMs
2837 
2838 
2839   Sample usage:
2840 .vb
2841     DMRegister("my_da", MyDMCreate);
2842 .ve
2843 
2844   Then, your DM type can be chosen with the procedural interface via
2845 .vb
2846     DMCreate(MPI_Comm, DM *);
2847     DMSetType(DM,"my_da");
2848 .ve
2849    or at runtime via the option
2850 .vb
2851     -da_type my_da
2852 .ve
2853 
2854   Level: advanced
2855 
2856 .keywords: DM, register
2857 .seealso: DMRegisterAll(), DMRegisterDestroy()
2858 
2859 @*/
2860 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
2861 {
2862   PetscErrorCode ierr;
2863 
2864   PetscFunctionBegin;
2865   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
2866   PetscFunctionReturn(0);
2867 }
2868 
2869 #undef __FUNCT__
2870 #define __FUNCT__ "DMLoad"
2871 /*@C
2872   DMLoad - Loads a DM that has been stored in binary  with DMView().
2873 
2874   Collective on PetscViewer
2875 
2876   Input Parameters:
2877 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
2878            some related function before a call to DMLoad().
2879 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
2880            HDF5 file viewer, obtained from PetscViewerHDF5Open()
2881 
2882    Level: intermediate
2883 
2884   Notes:
2885    The type is determined by the data in the file, any type set into the DM before this call is ignored.
2886 
2887   Notes for advanced users:
2888   Most users should not need to know the details of the binary storage
2889   format, since DMLoad() and DMView() completely hide these details.
2890   But for anyone who's interested, the standard binary matrix storage
2891   format is
2892 .vb
2893      has not yet been determined
2894 .ve
2895 
2896 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
2897 @*/
2898 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
2899 {
2900   PetscBool      isbinary, ishdf5;
2901   PetscErrorCode ierr;
2902 
2903   PetscFunctionBegin;
2904   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
2905   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
2906   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
2907   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2908   if (isbinary) {
2909     PetscInt classid;
2910     char     type[256];
2911 
2912     ierr = PetscViewerBinaryRead(viewer,&classid,1,PETSC_INT);CHKERRQ(ierr);
2913     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
2914     ierr = PetscViewerBinaryRead(viewer,type,256,PETSC_CHAR);CHKERRQ(ierr);
2915     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
2916     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2917   } else if (ishdf5) {
2918     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2919   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
2920   PetscFunctionReturn(0);
2921 }
2922 
2923 /******************************** FEM Support **********************************/
2924 
2925 #undef __FUNCT__
2926 #define __FUNCT__ "DMPrintCellVector"
2927 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
2928 {
2929   PetscInt       f;
2930   PetscErrorCode ierr;
2931 
2932   PetscFunctionBegin;
2933   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2934   for (f = 0; f < len; ++f) {
2935     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
2936   }
2937   PetscFunctionReturn(0);
2938 }
2939 
2940 #undef __FUNCT__
2941 #define __FUNCT__ "DMPrintCellMatrix"
2942 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
2943 {
2944   PetscInt       f, g;
2945   PetscErrorCode ierr;
2946 
2947   PetscFunctionBegin;
2948   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2949   for (f = 0; f < rows; ++f) {
2950     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
2951     for (g = 0; g < cols; ++g) {
2952       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
2953     }
2954     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
2955   }
2956   PetscFunctionReturn(0);
2957 }
2958 
2959 #undef __FUNCT__
2960 #define __FUNCT__ "DMPrintLocalVec"
2961 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
2962 {
2963   PetscMPIInt    rank, numProcs;
2964   PetscInt       p;
2965   PetscErrorCode ierr;
2966 
2967   PetscFunctionBegin;
2968   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2969   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
2970   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
2971   for (p = 0; p < numProcs; ++p) {
2972     if (p == rank) {
2973       Vec x;
2974 
2975       ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
2976       ierr = VecCopy(X, x);CHKERRQ(ierr);
2977       ierr = VecChop(x, tol);CHKERRQ(ierr);
2978       ierr = VecView(x, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2979       ierr = VecDestroy(&x);CHKERRQ(ierr);
2980       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2981     }
2982     ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
2983   }
2984   PetscFunctionReturn(0);
2985 }
2986 
2987 #undef __FUNCT__
2988 #define __FUNCT__ "DMGetDefaultSection"
2989 /*@
2990   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
2991 
2992   Input Parameter:
2993 . dm - The DM
2994 
2995   Output Parameter:
2996 . section - The PetscSection
2997 
2998   Level: intermediate
2999 
3000   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3001 
3002 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3003 @*/
3004 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3005 {
3006   PetscErrorCode ierr;
3007 
3008   PetscFunctionBegin;
3009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3010   PetscValidPointer(section, 2);
3011   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3012     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3013     ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, "dm_", "-petscsection_view");CHKERRQ(ierr);
3014   }
3015   *section = dm->defaultSection;
3016   PetscFunctionReturn(0);
3017 }
3018 
3019 #undef __FUNCT__
3020 #define __FUNCT__ "DMSetDefaultSection"
3021 /*@
3022   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
3023 
3024   Input Parameters:
3025 + dm - The DM
3026 - section - The PetscSection
3027 
3028   Level: intermediate
3029 
3030   Note: Any existing Section will be destroyed
3031 
3032 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3033 @*/
3034 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3035 {
3036   PetscInt       numFields;
3037   PetscInt       f;
3038   PetscErrorCode ierr;
3039 
3040   PetscFunctionBegin;
3041   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3042   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3043   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3044   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3045   dm->defaultSection = section;
3046   ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);
3047   if (numFields) {
3048     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3049     for (f = 0; f < numFields; ++f) {
3050       PetscObject disc;
3051       const char *name;
3052 
3053       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3054       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3055       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3056     }
3057   }
3058   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3059   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3060   PetscFunctionReturn(0);
3061 }
3062 
3063 #undef __FUNCT__
3064 #define __FUNCT__ "DMGetDefaultConstraints"
3065 /*@
3066   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3067 
3068   not collective
3069 
3070   Input Parameter:
3071 . dm - The DM
3072 
3073   Output Parameter:
3074 + 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.
3075 - 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.
3076 
3077   Level: advanced
3078 
3079   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3080 
3081 .seealso: DMSetDefaultConstraints()
3082 @*/
3083 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3084 {
3085   PetscErrorCode ierr;
3086 
3087   PetscFunctionBegin;
3088   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3089   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3090   if (section) {*section = dm->defaultConstraintSection;}
3091   if (mat) {*mat = dm->defaultConstraintMat;}
3092   PetscFunctionReturn(0);
3093 }
3094 
3095 #undef __FUNCT__
3096 #define __FUNCT__ "DMSetDefaultConstraints"
3097 /*@
3098   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3099 
3100   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().
3101 
3102   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.
3103 
3104   collective on dm
3105 
3106   Input Parameters:
3107 + dm - The DM
3108 + section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (PETSC_COMM_SELF or derivative).
3109 - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section:  NULL indicates no constraints.  Must have a local communicator (PETSC_COMM_SELF or derivative).
3110 
3111   Level: advanced
3112 
3113   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3114 
3115 .seealso: DMGetDefaultConstraints()
3116 @*/
3117 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3118 {
3119   PetscMPIInt result;
3120   PetscErrorCode ierr;
3121 
3122   PetscFunctionBegin;
3123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3124   if (section) {
3125     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3126     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3127     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3128   }
3129   if (mat) {
3130     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3131     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3132     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3133   }
3134   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3135   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3136   dm->defaultConstraintSection = section;
3137   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3138   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3139   dm->defaultConstraintMat = mat;
3140   PetscFunctionReturn(0);
3141 }
3142 
3143 #undef __FUNCT__
3144 #define __FUNCT__ "DMGetDefaultGlobalSection"
3145 /*@
3146   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3147 
3148   Collective on DM
3149 
3150   Input Parameter:
3151 . dm - The DM
3152 
3153   Output Parameter:
3154 . section - The PetscSection
3155 
3156   Level: intermediate
3157 
3158   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3159 
3160 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3161 @*/
3162 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3163 {
3164   PetscErrorCode ierr;
3165 
3166   PetscFunctionBegin;
3167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3168   PetscValidPointer(section, 2);
3169   if (!dm->defaultGlobalSection) {
3170     PetscSection s;
3171 
3172     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3173     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3174     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3175     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3176     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3177     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3178   }
3179   *section = dm->defaultGlobalSection;
3180   PetscFunctionReturn(0);
3181 }
3182 
3183 #undef __FUNCT__
3184 #define __FUNCT__ "DMSetDefaultGlobalSection"
3185 /*@
3186   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3187 
3188   Input Parameters:
3189 + dm - The DM
3190 - section - The PetscSection, or NULL
3191 
3192   Level: intermediate
3193 
3194   Note: Any existing Section will be destroyed
3195 
3196 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3197 @*/
3198 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3199 {
3200   PetscErrorCode ierr;
3201 
3202   PetscFunctionBegin;
3203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3204   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3205   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3206   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3207   dm->defaultGlobalSection = section;
3208   PetscFunctionReturn(0);
3209 }
3210 
3211 #undef __FUNCT__
3212 #define __FUNCT__ "DMGetDefaultSF"
3213 /*@
3214   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3215   it is created from the default PetscSection layouts in the DM.
3216 
3217   Input Parameter:
3218 . dm - The DM
3219 
3220   Output Parameter:
3221 . sf - The PetscSF
3222 
3223   Level: intermediate
3224 
3225   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3226 
3227 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3228 @*/
3229 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3230 {
3231   PetscInt       nroots;
3232   PetscErrorCode ierr;
3233 
3234   PetscFunctionBegin;
3235   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3236   PetscValidPointer(sf, 2);
3237   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3238   if (nroots < 0) {
3239     PetscSection section, gSection;
3240 
3241     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3242     if (section) {
3243       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3244       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3245     } else {
3246       *sf = NULL;
3247       PetscFunctionReturn(0);
3248     }
3249   }
3250   *sf = dm->defaultSF;
3251   PetscFunctionReturn(0);
3252 }
3253 
3254 #undef __FUNCT__
3255 #define __FUNCT__ "DMSetDefaultSF"
3256 /*@
3257   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3258 
3259   Input Parameters:
3260 + dm - The DM
3261 - sf - The PetscSF
3262 
3263   Level: intermediate
3264 
3265   Note: Any previous SF is destroyed
3266 
3267 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3268 @*/
3269 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3270 {
3271   PetscErrorCode ierr;
3272 
3273   PetscFunctionBegin;
3274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3275   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3276   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3277   dm->defaultSF = sf;
3278   PetscFunctionReturn(0);
3279 }
3280 
3281 #undef __FUNCT__
3282 #define __FUNCT__ "DMCreateDefaultSF"
3283 /*@C
3284   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3285   describing the data layout.
3286 
3287   Input Parameters:
3288 + dm - The DM
3289 . localSection - PetscSection describing the local data layout
3290 - globalSection - PetscSection describing the global data layout
3291 
3292   Level: intermediate
3293 
3294 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3295 @*/
3296 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3297 {
3298   MPI_Comm       comm;
3299   PetscLayout    layout;
3300   const PetscInt *ranges;
3301   PetscInt       *local;
3302   PetscSFNode    *remote;
3303   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3304   PetscMPIInt    size, rank;
3305   PetscErrorCode ierr;
3306 
3307   PetscFunctionBegin;
3308   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3309   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3310   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3311   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3312   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3313   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3314   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3315   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3316   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3317   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3318   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3319   for (p = pStart; p < pEnd; ++p) {
3320     PetscInt gdof, gcdof;
3321 
3322     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3323     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3324     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));
3325     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3326   }
3327   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3328   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3329   for (p = pStart, l = 0; p < pEnd; ++p) {
3330     const PetscInt *cind;
3331     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3332 
3333     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3334     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3335     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3336     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3337     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3338     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3339     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3340     if (!gdof) continue; /* Censored point */
3341     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3342     if (gsize != dof-cdof) {
3343       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);
3344       cdof = 0; /* Ignore constraints */
3345     }
3346     for (d = 0, c = 0; d < dof; ++d) {
3347       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3348       local[l+d-c] = off+d;
3349     }
3350     if (gdof < 0) {
3351       for (d = 0; d < gsize; ++d, ++l) {
3352         PetscInt offset = -(goff+1) + d, r;
3353 
3354         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3355         if (r < 0) r = -(r+2);
3356         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);
3357         remote[l].rank  = r;
3358         remote[l].index = offset - ranges[r];
3359       }
3360     } else {
3361       for (d = 0; d < gsize; ++d, ++l) {
3362         remote[l].rank  = rank;
3363         remote[l].index = goff+d - ranges[rank];
3364       }
3365     }
3366   }
3367   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3368   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3369   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3370   PetscFunctionReturn(0);
3371 }
3372 
3373 #undef __FUNCT__
3374 #define __FUNCT__ "DMGetPointSF"
3375 /*@
3376   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3377 
3378   Input Parameter:
3379 . dm - The DM
3380 
3381   Output Parameter:
3382 . sf - The PetscSF
3383 
3384   Level: intermediate
3385 
3386   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3387 
3388 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3389 @*/
3390 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3391 {
3392   PetscFunctionBegin;
3393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3394   PetscValidPointer(sf, 2);
3395   *sf = dm->sf;
3396   PetscFunctionReturn(0);
3397 }
3398 
3399 #undef __FUNCT__
3400 #define __FUNCT__ "DMSetPointSF"
3401 /*@
3402   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3403 
3404   Input Parameters:
3405 + dm - The DM
3406 - sf - The PetscSF
3407 
3408   Level: intermediate
3409 
3410 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3411 @*/
3412 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3413 {
3414   PetscErrorCode ierr;
3415 
3416   PetscFunctionBegin;
3417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3418   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3419   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3420   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3421   dm->sf = sf;
3422   PetscFunctionReturn(0);
3423 }
3424 
3425 #undef __FUNCT__
3426 #define __FUNCT__ "DMGetDS"
3427 /*@
3428   DMGetDS - Get the PetscDS
3429 
3430   Input Parameter:
3431 . dm - The DM
3432 
3433   Output Parameter:
3434 . prob - The PetscDS
3435 
3436   Level: developer
3437 
3438 .seealso: DMSetDS()
3439 @*/
3440 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3441 {
3442   PetscFunctionBegin;
3443   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3444   PetscValidPointer(prob, 2);
3445   *prob = dm->prob;
3446   PetscFunctionReturn(0);
3447 }
3448 
3449 #undef __FUNCT__
3450 #define __FUNCT__ "DMSetDS"
3451 /*@
3452   DMSetDS - Set the PetscDS
3453 
3454   Input Parameters:
3455 + dm - The DM
3456 - prob - The PetscDS
3457 
3458   Level: developer
3459 
3460 .seealso: DMGetDS()
3461 @*/
3462 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3463 {
3464   PetscErrorCode ierr;
3465 
3466   PetscFunctionBegin;
3467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3468   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3469   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3470   dm->prob = prob;
3471   ierr = PetscObjectReference((PetscObject) dm->prob);CHKERRQ(ierr);
3472   PetscFunctionReturn(0);
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMGetNumFields"
3477 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3478 {
3479   PetscErrorCode ierr;
3480 
3481   PetscFunctionBegin;
3482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3483   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3484   PetscFunctionReturn(0);
3485 }
3486 
3487 #undef __FUNCT__
3488 #define __FUNCT__ "DMSetNumFields"
3489 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3490 {
3491   PetscInt       Nf, f;
3492   PetscErrorCode ierr;
3493 
3494   PetscFunctionBegin;
3495   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3496   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3497   for (f = Nf; f < numFields; ++f) {
3498     PetscContainer obj;
3499 
3500     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3501     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3502     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3503   }
3504   PetscFunctionReturn(0);
3505 }
3506 
3507 #undef __FUNCT__
3508 #define __FUNCT__ "DMGetField"
3509 /*@
3510   DMGetField - Return the discretization object for a given DM field
3511 
3512   Not collective
3513 
3514   Input Parameters:
3515 + dm - The DM
3516 - f  - The field number
3517 
3518   Output Parameter:
3519 . field - The discretization object
3520 
3521   Level: developer
3522 
3523 .seealso: DMSetField()
3524 @*/
3525 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3526 {
3527   PetscErrorCode ierr;
3528 
3529   PetscFunctionBegin;
3530   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3531   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3532   PetscFunctionReturn(0);
3533 }
3534 
3535 #undef __FUNCT__
3536 #define __FUNCT__ "DMSetField"
3537 /*@
3538   DMSetField - Set the discretization object for a given DM field
3539 
3540   Logically collective on DM
3541 
3542   Input Parameters:
3543 + dm - The DM
3544 . f  - The field number
3545 - field - The discretization object
3546 
3547   Level: developer
3548 
3549 .seealso: DMGetField()
3550 @*/
3551 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3552 {
3553   PetscErrorCode ierr;
3554 
3555   PetscFunctionBegin;
3556   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3557   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3558   PetscFunctionReturn(0);
3559 }
3560 
3561 #undef __FUNCT__
3562 #define __FUNCT__ "DMRestrictHook_Coordinates"
3563 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3564 {
3565   DM dm_coord,dmc_coord;
3566   PetscErrorCode ierr;
3567   Vec coords,ccoords;
3568   VecScatter scat;
3569   PetscFunctionBegin;
3570   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3571   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3572   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3573   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3574   if (coords && !ccoords) {
3575     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3576     ierr = DMCreateInjection(dmc_coord,dm_coord,&scat);CHKERRQ(ierr);
3577     ierr = VecScatterBegin(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3578     ierr = VecScatterEnd(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3579     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3580     ierr = VecScatterDestroy(&scat);CHKERRQ(ierr);
3581     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3582   }
3583   PetscFunctionReturn(0);
3584 }
3585 
3586 #undef __FUNCT__
3587 #define __FUNCT__ "DMSubDomainHook_Coordinates"
3588 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3589 {
3590   DM dm_coord,subdm_coord;
3591   PetscErrorCode ierr;
3592   Vec coords,ccoords,clcoords;
3593   VecScatter *scat_i,*scat_g;
3594   PetscFunctionBegin;
3595   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3596   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3597   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3598   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3599   if (coords && !ccoords) {
3600     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3601     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3602     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3603     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3604     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3605     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3606     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3607     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3608     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3609     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3610     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3611     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3612     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3613     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3614     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3615   }
3616   PetscFunctionReturn(0);
3617 }
3618 
3619 #undef __FUNCT__
3620 #define __FUNCT__ "DMGetDimension"
3621 /*@
3622   DMGetDimension - Return the topological dimension of the DM
3623 
3624   Not collective
3625 
3626   Input Parameter:
3627 . dm - The DM
3628 
3629   Output Parameter:
3630 . dim - The topological dimension
3631 
3632   Level: beginner
3633 
3634 .seealso: DMSetDimension(), DMCreate()
3635 @*/
3636 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3637 {
3638   PetscFunctionBegin;
3639   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3640   PetscValidPointer(dim, 2);
3641   *dim = dm->dim;
3642   PetscFunctionReturn(0);
3643 }
3644 
3645 #undef __FUNCT__
3646 #define __FUNCT__ "DMSetDimension"
3647 /*@
3648   DMSetDimension - Set the topological dimension of the DM
3649 
3650   Collective on dm
3651 
3652   Input Parameters:
3653 + dm - The DM
3654 - dim - The topological dimension
3655 
3656   Level: beginner
3657 
3658 .seealso: DMGetDimension(), DMCreate()
3659 @*/
3660 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3661 {
3662   PetscFunctionBegin;
3663   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3664   PetscValidLogicalCollectiveInt(dm, dim, 2);
3665   dm->dim = dim;
3666   PetscFunctionReturn(0);
3667 }
3668 
3669 #undef __FUNCT__
3670 #define __FUNCT__ "DMGetDimPoints"
3671 /*@
3672   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3673 
3674   Collective on DM
3675 
3676   Input Parameters:
3677 + dm - the DM
3678 - dim - the dimension
3679 
3680   Output Parameters:
3681 + pStart - The first point of the given dimension
3682 . pEnd - The first point following points of the given dimension
3683 
3684   Note:
3685   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3686   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3687   then the interval is empty.
3688 
3689   Level: intermediate
3690 
3691 .keywords: point, Hasse Diagram, dimension
3692 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3693 @*/
3694 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3695 {
3696   PetscInt       d;
3697   PetscErrorCode ierr;
3698 
3699   PetscFunctionBegin;
3700   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3701   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3702   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3703   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3704   PetscFunctionReturn(0);
3705 }
3706 
3707 #undef __FUNCT__
3708 #define __FUNCT__ "DMSetCoordinates"
3709 /*@
3710   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3711 
3712   Collective on DM
3713 
3714   Input Parameters:
3715 + dm - the DM
3716 - c - coordinate vector
3717 
3718   Note:
3719   The coordinates do include those for ghost points, which are in the local vector
3720 
3721   Level: intermediate
3722 
3723 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3724 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3725 @*/
3726 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3727 {
3728   PetscErrorCode ierr;
3729 
3730   PetscFunctionBegin;
3731   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3732   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3733   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3734   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3735   dm->coordinates = c;
3736   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3737   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3738   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3739   PetscFunctionReturn(0);
3740 }
3741 
3742 #undef __FUNCT__
3743 #define __FUNCT__ "DMSetCoordinatesLocal"
3744 /*@
3745   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3746 
3747   Collective on DM
3748 
3749    Input Parameters:
3750 +  dm - the DM
3751 -  c - coordinate vector
3752 
3753   Note:
3754   The coordinates of ghost points can be set using DMSetCoordinates()
3755   followed by DMGetCoordinatesLocal(). This is intended to enable the
3756   setting of ghost coordinates outside of the domain.
3757 
3758   Level: intermediate
3759 
3760 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3761 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3762 @*/
3763 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3764 {
3765   PetscErrorCode ierr;
3766 
3767   PetscFunctionBegin;
3768   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3769   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3770   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3771   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3772 
3773   dm->coordinatesLocal = c;
3774 
3775   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3776   PetscFunctionReturn(0);
3777 }
3778 
3779 #undef __FUNCT__
3780 #define __FUNCT__ "DMGetCoordinates"
3781 /*@
3782   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
3783 
3784   Not Collective
3785 
3786   Input Parameter:
3787 . dm - the DM
3788 
3789   Output Parameter:
3790 . c - global coordinate vector
3791 
3792   Note:
3793   This is a borrowed reference, so the user should NOT destroy this vector
3794 
3795   Each process has only the local coordinates (does NOT have the ghost coordinates).
3796 
3797   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3798   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3799 
3800   Level: intermediate
3801 
3802 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3803 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
3804 @*/
3805 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
3806 {
3807   PetscErrorCode ierr;
3808 
3809   PetscFunctionBegin;
3810   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3811   PetscValidPointer(c,2);
3812   if (!dm->coordinates && dm->coordinatesLocal) {
3813     DM cdm = NULL;
3814 
3815     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3816     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
3817     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
3818     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3819     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3820   }
3821   *c = dm->coordinates;
3822   PetscFunctionReturn(0);
3823 }
3824 
3825 #undef __FUNCT__
3826 #define __FUNCT__ "DMGetCoordinatesLocal"
3827 /*@
3828   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
3829 
3830   Collective on DM
3831 
3832   Input Parameter:
3833 . dm - the DM
3834 
3835   Output Parameter:
3836 . c - coordinate vector
3837 
3838   Note:
3839   This is a borrowed reference, so the user should NOT destroy this vector
3840 
3841   Each process has the local and ghost coordinates
3842 
3843   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3844   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3845 
3846   Level: intermediate
3847 
3848 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3849 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
3850 @*/
3851 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
3852 {
3853   PetscErrorCode ierr;
3854 
3855   PetscFunctionBegin;
3856   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3857   PetscValidPointer(c,2);
3858   if (!dm->coordinatesLocal && dm->coordinates) {
3859     DM cdm = NULL;
3860 
3861     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3862     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
3863     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
3864     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3865     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3866   }
3867   *c = dm->coordinatesLocal;
3868   PetscFunctionReturn(0);
3869 }
3870 
3871 #undef __FUNCT__
3872 #define __FUNCT__ "DMGetCoordinateDM"
3873 /*@
3874   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
3875 
3876   Collective on DM
3877 
3878   Input Parameter:
3879 . dm - the DM
3880 
3881   Output Parameter:
3882 . cdm - coordinate DM
3883 
3884   Level: intermediate
3885 
3886 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3887 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3888 @*/
3889 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
3890 {
3891   PetscErrorCode ierr;
3892 
3893   PetscFunctionBegin;
3894   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3895   PetscValidPointer(cdm,2);
3896   if (!dm->coordinateDM) {
3897     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
3898     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
3899   }
3900   *cdm = dm->coordinateDM;
3901   PetscFunctionReturn(0);
3902 }
3903 
3904 #undef __FUNCT__
3905 #define __FUNCT__ "DMSetCoordinateDM"
3906 /*@
3907   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
3908 
3909   Logically Collective on DM
3910 
3911   Input Parameters:
3912 + dm - the DM
3913 - cdm - coordinate DM
3914 
3915   Level: intermediate
3916 
3917 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3918 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3919 @*/
3920 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
3921 {
3922   PetscErrorCode ierr;
3923 
3924   PetscFunctionBegin;
3925   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3926   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
3927   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
3928   dm->coordinateDM = cdm;
3929   ierr = PetscObjectReference((PetscObject) dm->coordinateDM);CHKERRQ(ierr);
3930   PetscFunctionReturn(0);
3931 }
3932 
3933 #undef __FUNCT__
3934 #define __FUNCT__ "DMGetCoordinateDim"
3935 /*@
3936   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
3937 
3938   Not Collective
3939 
3940   Input Parameter:
3941 . dm - The DM object
3942 
3943   Output Parameter:
3944 . dim - The embedding dimension
3945 
3946   Level: intermediate
3947 
3948 .keywords: mesh, coordinates
3949 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
3950 @*/
3951 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
3952 {
3953   PetscFunctionBegin;
3954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3955   PetscValidPointer(dim, 2);
3956   if (dm->dimEmbed == PETSC_DEFAULT) {
3957     dm->dimEmbed = dm->dim;
3958   }
3959   *dim = dm->dimEmbed;
3960   PetscFunctionReturn(0);
3961 }
3962 
3963 #undef __FUNCT__
3964 #define __FUNCT__ "DMSetCoordinateDim"
3965 /*@
3966   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
3967 
3968   Not Collective
3969 
3970   Input Parameters:
3971 + dm  - The DM object
3972 - dim - The embedding dimension
3973 
3974   Level: intermediate
3975 
3976 .keywords: mesh, coordinates
3977 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
3978 @*/
3979 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
3980 {
3981   PetscFunctionBegin;
3982   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3983   dm->dimEmbed = dim;
3984   PetscFunctionReturn(0);
3985 }
3986 
3987 #undef __FUNCT__
3988 #define __FUNCT__ "DMGetCoordinateSection"
3989 /*@
3990   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
3991 
3992   Not Collective
3993 
3994   Input Parameter:
3995 . dm - The DM object
3996 
3997   Output Parameter:
3998 . section - The PetscSection object
3999 
4000   Level: intermediate
4001 
4002 .keywords: mesh, coordinates
4003 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4004 @*/
4005 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4006 {
4007   DM             cdm;
4008   PetscErrorCode ierr;
4009 
4010   PetscFunctionBegin;
4011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4012   PetscValidPointer(section, 2);
4013   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4014   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4015   PetscFunctionReturn(0);
4016 }
4017 
4018 #undef __FUNCT__
4019 #define __FUNCT__ "DMSetCoordinateSection"
4020 /*@
4021   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4022 
4023   Not Collective
4024 
4025   Input Parameters:
4026 + dm      - The DM object
4027 . dim     - The embedding dimension, or PETSC_DETERMINE
4028 - section - The PetscSection object
4029 
4030   Level: intermediate
4031 
4032 .keywords: mesh, coordinates
4033 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4034 @*/
4035 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4036 {
4037   DM             cdm;
4038   PetscErrorCode ierr;
4039 
4040   PetscFunctionBegin;
4041   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4042   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4043   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4044   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4045   if (dim == PETSC_DETERMINE) {
4046     PetscInt d = dim;
4047     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4048 
4049     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4050     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4051     pStart = PetscMax(vStart, pStart);
4052     pEnd   = PetscMin(vEnd, pEnd);
4053     for (v = pStart; v < pEnd; ++v) {
4054       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4055       if (dd) {d = dd; break;}
4056     }
4057     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4058   }
4059   PetscFunctionReturn(0);
4060 }
4061 
4062 #undef __FUNCT__
4063 #define __FUNCT__ "DMGetPeriodicity"
4064 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L)
4065 {
4066   PetscFunctionBegin;
4067   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4068   if (L)       *L       = dm->L;
4069   if (maxCell) *maxCell = dm->maxCell;
4070   PetscFunctionReturn(0);
4071 }
4072 
4073 #undef __FUNCT__
4074 #define __FUNCT__ "DMSetPeriodicity"
4075 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[])
4076 {
4077   Vec            coordinates;
4078   PetscInt       dim, d;
4079   PetscErrorCode ierr;
4080 
4081   PetscFunctionBegin;
4082   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4083   ierr = PetscFree(dm->L);CHKERRQ(ierr);
4084   ierr = PetscFree(dm->maxCell);CHKERRQ(ierr);
4085   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4086   ierr = VecGetBlockSize(coordinates, &dim);CHKERRQ(ierr);
4087   ierr = PetscMalloc1(dim,&dm->L);CHKERRQ(ierr);
4088   ierr = PetscMalloc1(dim,&dm->maxCell);CHKERRQ(ierr);
4089   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d];}
4090   PetscFunctionReturn(0);
4091 }
4092 
4093 #undef __FUNCT__
4094 #define __FUNCT__ "DMLocatePoints"
4095 /*@
4096   DMLocatePoints - Locate the points in v in the mesh and return an IS of the containing cells
4097 
4098   Not collective
4099 
4100   Input Parameters:
4101 + dm - The DM
4102 - v - The Vec of points
4103 
4104   Output Parameter:
4105 . cells - The local cell numbers for cells which contain the points
4106 
4107   Level: developer
4108 
4109 .keywords: point location, mesh
4110 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4111 @*/
4112 PetscErrorCode DMLocatePoints(DM dm, Vec v, IS *cells)
4113 {
4114   PetscErrorCode ierr;
4115 
4116   PetscFunctionBegin;
4117   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4118   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4119   PetscValidPointer(cells,3);
4120   if (dm->ops->locatepoints) {
4121     ierr = (*dm->ops->locatepoints)(dm,v,cells);CHKERRQ(ierr);
4122   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4123   PetscFunctionReturn(0);
4124 }
4125 
4126 #undef __FUNCT__
4127 #define __FUNCT__ "DMGetOutputDM"
4128 /*@
4129   DMGetOutputDM - Retrieve the DM associated with the layout for output
4130 
4131   Input Parameter:
4132 . dm - The original DM
4133 
4134   Output Parameter:
4135 . odm - The DM which provides the layout for output
4136 
4137   Level: intermediate
4138 
4139 .seealso: VecView(), DMGetDefaultGlobalSection()
4140 @*/
4141 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4142 {
4143   PetscSection   section;
4144   PetscBool      hasConstraints;
4145   PetscErrorCode ierr;
4146 
4147   PetscFunctionBegin;
4148   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4149   PetscValidPointer(odm,2);
4150   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4151   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4152   if (!hasConstraints) {
4153     *odm = dm;
4154     PetscFunctionReturn(0);
4155   }
4156   if (!dm->dmBC) {
4157     PetscSection newSection, gsection;
4158     PetscSF      sf;
4159 
4160     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4161     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4162     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4163     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4164     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4165     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, &gsection);CHKERRQ(ierr);
4166     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4167     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4168   }
4169   *odm = dm->dmBC;
4170   PetscFunctionReturn(0);
4171 }
4172 
4173 #undef __FUNCT__
4174 #define __FUNCT__ "DMGetOutputSequenceNumber"
4175 /*@
4176   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4177 
4178   Input Parameter:
4179 . dm - The original DM
4180 
4181   Output Parameters:
4182 + num - The output sequence number
4183 - val - The output sequence value
4184 
4185   Level: intermediate
4186 
4187   Note: This is intended for output that should appear in sequence, for instance
4188   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4189 
4190 .seealso: VecView()
4191 @*/
4192 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4193 {
4194   PetscFunctionBegin;
4195   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4196   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4197   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4198   PetscFunctionReturn(0);
4199 }
4200 
4201 #undef __FUNCT__
4202 #define __FUNCT__ "DMSetOutputSequenceNumber"
4203 /*@
4204   DMSetOutputSequenceNumber - Set the sequence number/value for output
4205 
4206   Input Parameters:
4207 + dm - The original DM
4208 . num - The output sequence number
4209 - val - The output sequence value
4210 
4211   Level: intermediate
4212 
4213   Note: This is intended for output that should appear in sequence, for instance
4214   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4215 
4216 .seealso: VecView()
4217 @*/
4218 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4219 {
4220   PetscFunctionBegin;
4221   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4222   dm->outputSequenceNum = num;
4223   dm->outputSequenceVal = val;
4224   PetscFunctionReturn(0);
4225 }
4226 
4227 #undef __FUNCT__
4228 #define __FUNCT__ "DMOutputSequenceLoad"
4229 /*@C
4230   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4231 
4232   Input Parameters:
4233 + dm   - The original DM
4234 . name - The sequence name
4235 - num  - The output sequence number
4236 
4237   Output Parameter:
4238 . val  - The output sequence value
4239 
4240   Level: intermediate
4241 
4242   Note: This is intended for output that should appear in sequence, for instance
4243   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4244 
4245 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4246 @*/
4247 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4248 {
4249   PetscBool      ishdf5;
4250   PetscErrorCode ierr;
4251 
4252   PetscFunctionBegin;
4253   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4254   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4255   PetscValidPointer(val,4);
4256   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4257   if (ishdf5) {
4258 #if defined(PETSC_HAVE_HDF5)
4259     PetscScalar value;
4260 
4261     ierr = DMSequenceLoad_HDF5(dm, name, num, &value, viewer);CHKERRQ(ierr);
4262     *val = PetscRealPart(value);
4263 #endif
4264   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4265   PetscFunctionReturn(0);
4266 }
4267