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