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