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