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