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