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