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