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