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