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