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