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