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