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