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