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