Actual source code: dm.c
1: #include <petscvec.h>
2: #include <petsc/private/dmimpl.h>
3: #include <petsc/private/dmlabelimpl.h>
4: #include <petsc/private/petscdsimpl.h>
5: #include <petscdmplex.h>
6: #include <petscdmfield.h>
7: #include <petscsf.h>
8: #include <petscds.h>
10: #ifdef PETSC_HAVE_LIBCEED
11: #include <petscfeceed.h>
12: #endif
14: #if !defined(PETSC_HAVE_WINDOWS_COMPILERS)
15: #include <petsc/private/valgrind/memcheck.h>
16: #endif
18: PetscClassId DM_CLASSID;
19: PetscClassId DMLABEL_CLASSID;
20: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_AdaptInterpolator;
22: const char *const DMBoundaryTypes[] = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
23: const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "INVALID", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "INVALID", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType", "DM_BC_", NULL};
24: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism",
25: "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
26: const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
28: /*@
29: DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
30: algebraic solvers, time integrators, and optimization algorithms.
32: Collective
34: Input Parameter:
35: . comm - The communicator for the `DM` object
37: Output Parameter:
38: . dm - The `DM` object
40: Level: beginner
42: Notes:
43: See `DMType` for a brief summary of available `DM`.
45: The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
46: error when you try to use the dm.
48: .seealso: `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
49: @*/
50: PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
51: {
52: DM v;
53: PetscDS ds;
56: *dm = NULL;
57: DMInitializePackage();
59: PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);
61: ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
63: v->setupcalled = PETSC_FALSE;
64: v->setfromoptionscalled = PETSC_FALSE;
65: v->ltogmap = NULL;
66: v->bind_below = 0;
67: v->bs = 1;
68: v->coloringtype = IS_COLORING_GLOBAL;
69: PetscSFCreate(comm, &v->sf);
70: PetscSFCreate(comm, &v->sectionSF);
71: v->labels = NULL;
72: v->adjacency[0] = PETSC_FALSE;
73: v->adjacency[1] = PETSC_TRUE;
74: v->depthLabel = NULL;
75: v->celltypeLabel = NULL;
76: v->localSection = NULL;
77: v->globalSection = NULL;
78: v->defaultConstraint.section = NULL;
79: v->defaultConstraint.mat = NULL;
80: v->defaultConstraint.bias = NULL;
81: v->coordinates[0].dim = PETSC_DEFAULT;
82: v->coordinates[1].dim = PETSC_DEFAULT;
83: v->sparseLocalize = PETSC_TRUE;
84: v->dim = PETSC_DETERMINE;
85: {
86: PetscInt i;
87: for (i = 0; i < 10; ++i) {
88: v->nullspaceConstructors[i] = NULL;
89: v->nearnullspaceConstructors[i] = NULL;
90: }
91: }
92: PetscDSCreate(PETSC_COMM_SELF, &ds);
93: DMSetRegionDS(v, NULL, NULL, ds);
94: PetscDSDestroy(&ds);
95: PetscHMapAuxCreate(&v->auxData);
96: v->dmBC = NULL;
97: v->coarseMesh = NULL;
98: v->outputSequenceNum = -1;
99: v->outputSequenceVal = 0.0;
100: DMSetVecType(v, VECSTANDARD);
101: DMSetMatType(v, MATAIJ);
103: *dm = v;
104: return 0;
105: }
107: /*@
108: DMClone - Creates a `DM` object with the same topology as the original.
110: Collective
112: Input Parameter:
113: . dm - The original `DM` object
115: Output Parameter:
116: . newdm - The new `DM` object
118: Level: beginner
120: Notes:
121: For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
122: `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
123: share the `PetscSection` of the original `DM`.
125: The clone is considered set up if the original has been set up.
127: Use `DMConvert()` for a general way to create new `DM` from a given `DM`
129: .seealso: `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMSetType()`, `DMConvert()`
130: @*/
131: PetscErrorCode DMClone(DM dm, DM *newdm)
132: {
133: PetscSF sf;
134: Vec coords;
135: void *ctx;
136: PetscInt dim, cdim, i;
140: DMCreate(PetscObjectComm((PetscObject)dm), newdm);
141: DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL);
142: (*newdm)->leveldown = dm->leveldown;
143: (*newdm)->levelup = dm->levelup;
144: (*newdm)->prealloc_only = dm->prealloc_only;
145: PetscFree((*newdm)->vectype);
146: PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype);
147: PetscFree((*newdm)->mattype);
148: PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype);
149: DMGetDimension(dm, &dim);
150: DMSetDimension(*newdm, dim);
151: PetscTryTypeMethod(dm, clone, newdm);
152: (*newdm)->setupcalled = dm->setupcalled;
153: DMGetPointSF(dm, &sf);
154: DMSetPointSF(*newdm, sf);
155: DMGetApplicationContext(dm, &ctx);
156: DMSetApplicationContext(*newdm, ctx);
157: for (i = 0; i < 2; ++i) {
158: if (dm->coordinates[i].dm) {
159: DM ncdm;
160: PetscSection cs;
161: PetscInt pEnd = -1, pEndMax = -1;
163: DMGetLocalSection(dm->coordinates[i].dm, &cs);
164: if (cs) PetscSectionGetChart(cs, NULL, &pEnd);
165: MPI_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
166: if (pEndMax >= 0) {
167: DMClone(dm->coordinates[i].dm, &ncdm);
168: DMCopyDisc(dm->coordinates[i].dm, ncdm);
169: DMSetLocalSection(ncdm, cs);
170: if (i) DMSetCellCoordinateDM(*newdm, ncdm);
171: else DMSetCoordinateDM(*newdm, ncdm);
172: DMDestroy(&ncdm);
173: }
174: }
175: }
176: DMGetCoordinateDim(dm, &cdim);
177: DMSetCoordinateDim(*newdm, cdim);
178: DMGetCoordinatesLocal(dm, &coords);
179: if (coords) {
180: DMSetCoordinatesLocal(*newdm, coords);
181: } else {
182: DMGetCoordinates(dm, &coords);
183: if (coords) DMSetCoordinates(*newdm, coords);
184: }
185: DMGetCellCoordinatesLocal(dm, &coords);
186: if (coords) {
187: DMSetCellCoordinatesLocal(*newdm, coords);
188: } else {
189: DMGetCellCoordinates(dm, &coords);
190: if (coords) DMSetCellCoordinates(*newdm, coords);
191: }
192: {
193: const PetscReal *maxCell, *Lstart, *L;
195: DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
196: DMSetPeriodicity(*newdm, maxCell, Lstart, L);
197: }
198: {
199: PetscBool useCone, useClosure;
201: DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
202: DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
203: }
204: return 0;
205: }
207: /*@C
208: DMSetVecType - Sets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
210: Logically Collective on da
212: Input Parameters:
213: + da - initial distributed array
214: - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`
216: Options Database:
217: . -dm_vec_type ctype - the type of vector to create
219: Level: intermediate
221: .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
222: `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
223: @*/
224: PetscErrorCode DMSetVecType(DM da, VecType ctype)
225: {
227: PetscFree(da->vectype);
228: PetscStrallocpy(ctype, (char **)&da->vectype);
229: return 0;
230: }
232: /*@C
233: DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
235: Logically Collective on da
237: Input Parameter:
238: . da - initial distributed array
240: Output Parameter:
241: . ctype - the vector type
243: Level: intermediate
245: .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
246: @*/
247: PetscErrorCode DMGetVecType(DM da, VecType *ctype)
248: {
250: *ctype = da->vectype;
251: return 0;
252: }
254: /*@
255: VecGetDM - Gets the `DM` defining the data layout of the vector
257: Not collective
259: Input Parameter:
260: . v - The `Vec`
262: Output Parameter:
263: . dm - The `DM`
265: Level: intermediate
267: Note:
268: A `Vec` may not have a `DM` associated with it.
270: .seealso: `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
271: @*/
272: PetscErrorCode VecGetDM(Vec v, DM *dm)
273: {
276: PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm);
277: return 0;
278: }
280: /*@
281: VecSetDM - Sets the `DM` defining the data layout of the vector.
283: Not collective
285: Input Parameters:
286: + v - The `Vec`
287: - dm - The `DM`
289: Note:
290: This is rarely used, generally one uses `DMGetLocalVector()` or `DMGetGlobalVector()` to create a vector associated with a given `DM`
292: 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.
294: Level: developer
296: .seealso: `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
297: @*/
298: PetscErrorCode VecSetDM(Vec v, DM dm)
299: {
302: PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm);
303: return 0;
304: }
306: /*@C
307: DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
309: Logically Collective on dm
311: Input Parameters:
312: + dm - the `DM` context
313: - ctype - the matrix type
315: Options Database:
316: . -dm_is_coloring_type - global or local
318: Level: intermediate
320: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
321: `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
322: @*/
323: PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
324: {
326: dm->coloringtype = ctype;
327: return 0;
328: }
330: /*@C
331: DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
333: Logically Collective on dm
335: Input Parameter:
336: . dm - the `DM` context
338: Output Parameter:
339: . ctype - the matrix type
341: Options Database:
342: . -dm_is_coloring_type - global or local
344: Level: intermediate
346: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
347: `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
348: @*/
349: PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
350: {
352: *ctype = dm->coloringtype;
353: return 0;
354: }
356: /*@C
357: DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`
359: Logically Collective on dm
361: Input Parameters:
362: + dm - the `DM` context
363: - ctype - the matrix type, for example `MATMPIAIJ`
365: Options Database:
366: . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij
368: Level: intermediate
370: .seealso: `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`, `DMSetMatType()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
371: @*/
372: PetscErrorCode DMSetMatType(DM dm, MatType ctype)
373: {
375: PetscFree(dm->mattype);
376: PetscStrallocpy(ctype, (char **)&dm->mattype);
377: return 0;
378: }
380: /*@C
381: DMGetMatType - Gets the type of matrix created with `DMCreateMatrix()`
383: Logically Collective on dm
385: Input Parameter:
386: . dm - the `DM` context
388: Output Parameter:
389: . ctype - the matrix type
391: Level: intermediate
393: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`, `DMSetMatType()`, `DMGetMatType()`
394: @*/
395: PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
396: {
398: *ctype = dm->mattype;
399: return 0;
400: }
402: /*@
403: MatGetDM - Gets the `DM` defining the data layout of the matrix
405: Not collective
407: Input Parameter:
408: . A - The `Mat`
410: Output Parameter:
411: . dm - The `DM`
413: Level: intermediate
415: Note:
416: A matrix may not have a `DM` associated with it
418: Developer Note:
419: Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation
421: .seealso: `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
422: @*/
423: PetscErrorCode MatGetDM(Mat A, DM *dm)
424: {
427: PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm);
428: return 0;
429: }
431: /*@
432: MatSetDM - Sets the `DM` defining the data layout of the matrix
434: Not collective
436: Input Parameters:
437: + A - The Mat
438: - dm - The DM
440: Level: developer
442: Note:
443: This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`
445: Developer Note:
446: Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
447: the `Mat` through a `PetscObjectCompose()` operation
449: .seealso: `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
450: @*/
451: PetscErrorCode MatSetDM(Mat A, DM dm)
452: {
455: PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm);
456: return 0;
457: }
459: /*@C
460: DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database
462: Logically Collective on dm
464: Input Parameters:
465: + da - the `DM` context
466: - prefix - the prefix to prepend
468: Notes:
469: A hyphen (-) must NOT be given at the beginning of the prefix name.
470: The first character of all runtime options is AUTOMATICALLY the hyphen.
472: Level: advanced
474: .seealso: `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
475: @*/
476: PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
477: {
479: PetscObjectSetOptionsPrefix((PetscObject)dm, prefix);
480: if (dm->sf) PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix);
481: if (dm->sectionSF) PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix);
482: return 0;
483: }
485: /*@C
486: DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
487: `DM` options in the options database.
489: Logically Collective on dm
491: Input Parameters:
492: + dm - the `DM` context
493: - prefix - the string to append to the current prefix
495: Notes:
496: If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
497: A hyphen (-) must NOT be given at the beginning of the prefix name.
498: The first character of all runtime options is AUTOMATICALLY the hyphen.
500: Level: advanced
502: .seealso: `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
503: @*/
504: PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
505: {
507: PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix);
508: return 0;
509: }
511: /*@C
512: DMGetOptionsPrefix - Gets the prefix used for searching for all
513: DM options in the options database.
515: Not Collective
517: Input Parameters:
518: . dm - the `DM` context
520: Output Parameters:
521: . prefix - pointer to the prefix string used is returned
523: Fortran Note:
524: On the fortran side, the user should pass in a string 'prefix' of
525: sufficient length to hold the prefix.
527: Level: advanced
529: .seealso: `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
530: @*/
531: PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
532: {
534: PetscObjectGetOptionsPrefix((PetscObject)dm, prefix);
535: return 0;
536: }
538: static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
539: {
540: PetscInt refct = ((PetscObject)dm)->refct;
542: *ncrefct = 0;
543: if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
544: refct--;
545: if (recurseCoarse) {
546: PetscInt coarseCount;
548: DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount);
549: refct += coarseCount;
550: }
551: }
552: if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
553: refct--;
554: if (recurseFine) {
555: PetscInt fineCount;
557: DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount);
558: refct += fineCount;
559: }
560: }
561: *ncrefct = refct;
562: return 0;
563: }
565: /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
566: PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
567: {
568: DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct);
569: return 0;
570: }
572: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
573: {
574: DMLabelLink next = dm->labels;
576: /* destroy the labels */
577: while (next) {
578: DMLabelLink tmp = next->next;
580: if (next->label == dm->depthLabel) dm->depthLabel = NULL;
581: if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
582: DMLabelDestroy(&next->label);
583: PetscFree(next);
584: next = tmp;
585: }
586: dm->labels = NULL;
587: return 0;
588: }
590: PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
591: {
592: c->dim = PETSC_DEFAULT;
593: DMDestroy(&c->dm);
594: VecDestroy(&c->x);
595: VecDestroy(&c->xl);
596: DMFieldDestroy(&c->field);
597: return 0;
598: }
600: /*@C
601: DMDestroy - Destroys a `DM`.
603: Collective on dm
605: Input Parameter:
606: . dm - the `DM` object to destroy
608: Level: developer
610: .seealso: `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
611: @*/
612: PetscErrorCode DMDestroy(DM *dm)
613: {
614: PetscInt cnt;
615: DMNamedVecLink nlink, nnext;
617: if (!*dm) return 0;
620: /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
621: DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt);
622: --((PetscObject)(*dm))->refct;
623: if (--cnt > 0) {
624: *dm = NULL;
625: return 0;
626: }
627: if (((PetscObject)(*dm))->refct < 0) return 0;
628: ((PetscObject)(*dm))->refct = 0;
630: DMClearGlobalVectors(*dm);
631: DMClearLocalVectors(*dm);
633: nnext = (*dm)->namedglobal;
634: (*dm)->namedglobal = NULL;
635: for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named vectors */
636: nnext = nlink->next;
638: PetscFree(nlink->name);
639: VecDestroy(&nlink->X);
640: PetscFree(nlink);
641: }
642: nnext = (*dm)->namedlocal;
643: (*dm)->namedlocal = NULL;
644: for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named local vectors */
645: nnext = nlink->next;
647: PetscFree(nlink->name);
648: VecDestroy(&nlink->X);
649: PetscFree(nlink);
650: }
652: /* Destroy the list of hooks */
653: {
654: DMCoarsenHookLink link, next;
655: for (link = (*dm)->coarsenhook; link; link = next) {
656: next = link->next;
657: PetscFree(link);
658: }
659: (*dm)->coarsenhook = NULL;
660: }
661: {
662: DMRefineHookLink link, next;
663: for (link = (*dm)->refinehook; link; link = next) {
664: next = link->next;
665: PetscFree(link);
666: }
667: (*dm)->refinehook = NULL;
668: }
669: {
670: DMSubDomainHookLink link, next;
671: for (link = (*dm)->subdomainhook; link; link = next) {
672: next = link->next;
673: PetscFree(link);
674: }
675: (*dm)->subdomainhook = NULL;
676: }
677: {
678: DMGlobalToLocalHookLink link, next;
679: for (link = (*dm)->gtolhook; link; link = next) {
680: next = link->next;
681: PetscFree(link);
682: }
683: (*dm)->gtolhook = NULL;
684: }
685: {
686: DMLocalToGlobalHookLink link, next;
687: for (link = (*dm)->ltoghook; link; link = next) {
688: next = link->next;
689: PetscFree(link);
690: }
691: (*dm)->ltoghook = NULL;
692: }
693: /* Destroy the work arrays */
694: {
695: DMWorkLink link, next;
697: for (link = (*dm)->workin; link; link = next) {
698: next = link->next;
699: PetscFree(link->mem);
700: PetscFree(link);
701: }
702: (*dm)->workin = NULL;
703: }
704: /* destroy the labels */
705: DMDestroyLabelLinkList_Internal(*dm);
706: /* destroy the fields */
707: DMClearFields(*dm);
708: /* destroy the boundaries */
709: {
710: DMBoundary next = (*dm)->boundary;
711: while (next) {
712: DMBoundary b = next;
714: next = b->next;
715: PetscFree(b);
716: }
717: }
719: PetscObjectDestroy(&(*dm)->dmksp);
720: PetscObjectDestroy(&(*dm)->dmsnes);
721: PetscObjectDestroy(&(*dm)->dmts);
723: if ((*dm)->ctx && (*dm)->ctxdestroy) (*(*dm)->ctxdestroy)(&(*dm)->ctx);
724: MatFDColoringDestroy(&(*dm)->fd);
725: ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
726: PetscFree((*dm)->vectype);
727: PetscFree((*dm)->mattype);
729: PetscSectionDestroy(&(*dm)->localSection);
730: PetscSectionDestroy(&(*dm)->globalSection);
731: PetscLayoutDestroy(&(*dm)->map);
732: PetscSectionDestroy(&(*dm)->defaultConstraint.section);
733: MatDestroy(&(*dm)->defaultConstraint.mat);
734: PetscSFDestroy(&(*dm)->sf);
735: PetscSFDestroy(&(*dm)->sectionSF);
736: if ((*dm)->useNatural) {
737: if ((*dm)->sfNatural) PetscSFDestroy(&(*dm)->sfNatural);
738: PetscObjectDereference((PetscObject)(*dm)->sfMigration);
739: }
740: {
741: Vec *auxData;
742: PetscInt n, i, off = 0;
744: PetscHMapAuxGetSize((*dm)->auxData, &n);
745: PetscMalloc1(n, &auxData);
746: PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
747: for (i = 0; i < n; ++i) VecDestroy(&auxData[i]);
748: PetscFree(auxData);
749: PetscHMapAuxDestroy(&(*dm)->auxData);
750: }
751: if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) DMSetFineDM((*dm)->coarseMesh, NULL);
753: DMDestroy(&(*dm)->coarseMesh);
754: if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) DMSetCoarseDM((*dm)->fineMesh, NULL);
755: DMDestroy(&(*dm)->fineMesh);
756: PetscFree((*dm)->Lstart);
757: PetscFree((*dm)->L);
758: PetscFree((*dm)->maxCell);
759: DMDestroyCoordinates_Private(&(*dm)->coordinates[0]);
760: DMDestroyCoordinates_Private(&(*dm)->coordinates[1]);
761: if ((*dm)->transformDestroy) (*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);
762: DMDestroy(&(*dm)->transformDM);
763: VecDestroy(&(*dm)->transform);
765: DMClearDS(*dm);
766: DMDestroy(&(*dm)->dmBC);
767: /* if memory was published with SAWs then destroy it */
768: PetscObjectSAWsViewOff((PetscObject)*dm);
770: if ((*dm)->ops->destroy) (*(*dm)->ops->destroy)(*dm);
771: DMMonitorCancel(*dm);
772: #ifdef PETSC_HAVE_LIBCEED
773: CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
774: CeedDestroy(&(*dm)->ceed);
775: #endif
776: /* We do not destroy (*dm)->data here so that we can reference count backend objects */
777: PetscHeaderDestroy(dm);
778: return 0;
779: }
781: /*@
782: DMSetUp - sets up the data structures inside a `DM` object
784: Collective on dm
786: Input Parameter:
787: . dm - the `DM` object to setup
789: Level: intermediate
791: Note:
792: This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
794: .seealso: `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
795: @*/
796: PetscErrorCode DMSetUp(DM dm)
797: {
799: if (dm->setupcalled) return 0;
800: PetscTryTypeMethod(dm, setup);
801: dm->setupcalled = PETSC_TRUE;
802: return 0;
803: }
805: /*@
806: DMSetFromOptions - sets parameters in a `DM` from the options database
808: Collective on dm
810: Input Parameter:
811: . dm - the `DM` object to set options for
813: Options Database:
814: + -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
815: . -dm_vec_type <type> - type of vector to create inside `DM`
816: . -dm_mat_type <type> - type of matrix to create inside `DM`
817: . -dm_is_coloring_type - <global or local>
818: - -dm_bind_below <n> - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA`
820: DMPLEX Specific creation options
821: + -dm_plex_filename <str> - File containing a mesh
822: . -dm_plex_boundary_filename <str> - File containing a mesh boundary
823: . -dm_plex_name <str> - Name of the mesh in the file
824: . -dm_plex_shape <shape> - The domain shape, such as `DM_SHAPE_BOX`, `DM_SHAPE_SPHERE`, etc.
825: . -dm_plex_cell <ct> - Cell shape
826: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
827: . -dm_plex_dim <dim> - Set the topological dimension
828: . -dm_plex_simplex <bool> - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
829: . -dm_plex_interpolate <bool> - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
830: . -dm_plex_scale <sc> - Scale factor for mesh coordinates
831: . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension
832: . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box
833: . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box
834: . -dm_plex_box_bd <bx,by,bz> - Specify the `DMBoundaryType `for each direction
835: . -dm_plex_sphere_radius <r> - The sphere radius
836: . -dm_plex_ball_radius <r> - Radius of the ball
837: . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction
838: . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder
839: . -dm_plex_reorder <order> - Reorder the mesh using the specified algorithm
840: . -dm_refine_pre <n> - The number of refinements before distribution
841: . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution
842: . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution
843: . -dm_refine <n> - The number of refinements after distribution
844: . -dm_extrude <l> - Activate extrusion and specify the number of layers to extrude
845: . -dm_plex_transform_extrude_thickness <t> - The total thickness of extruded layers
846: . -dm_plex_transform_extrude_use_tensor <bool> - Use tensor cells when extruding
847: . -dm_plex_transform_extrude_symmetric <bool> - Extrude layers symmetrically about the surface
848: . -dm_plex_transform_extrude_normal <n0,...,nd> - Specify the extrusion direction
849: . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
850: . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary
851: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
852: . -dm_distribute <bool> - Flag to redistribute a mesh among processes
853: . -dm_distribute_overlap <n> - The size of the overlap halo
854: . -dm_plex_adj_cone <bool> - Set adjacency direction
855: - -dm_plex_adj_closure <bool> - Set adjacency size
857: DMPLEX Specific Checks
858: + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
859: . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
860: . -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()`
861: . -dm_plex_check_geometry - Check that cells have positive volume - `DMPlexCheckGeometry()`
862: . -dm_plex_check_pointsf - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
863: . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
864: - -dm_plex_check_all - Perform all the checks above
866: Level: intermediate
868: .seealso: `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
869: `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
870: `DMSetOptionsPrefix()`, `DM`, `DMType`, `DMPLEX`, `DMDA`
871: @*/
872: PetscErrorCode DMSetFromOptions(DM dm)
873: {
874: char typeName[256];
875: PetscBool flg;
878: dm->setfromoptionscalled = PETSC_TRUE;
879: if (dm->sf) PetscSFSetFromOptions(dm->sf);
880: if (dm->sectionSF) PetscSFSetFromOptions(dm->sectionSF);
881: PetscObjectOptionsBegin((PetscObject)dm);
882: PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL);
883: PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg);
884: if (flg) DMSetVecType(dm, typeName);
885: PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg);
886: if (flg) DMSetMatType(dm, typeName);
887: PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL);
888: PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg);
889: PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
890: /* process any options handlers added with PetscObjectAddOptionsHandler() */
891: PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject);
892: PetscOptionsEnd();
893: return 0;
894: }
896: /*@C
897: DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
899: Collective on dm
901: Input Parameters:
902: + dm - the `DM` object
903: . obj - optional object that provides the prefix for the options database (if NULL then the prefix in obj is used)
904: - optionname - option string that is used to activate viewing
906: Level: intermediate
908: Note:
909: See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
911: .seealso: `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`, `PetscObjectViewFromOptions()`
912: @*/
913: PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[])
914: {
916: PetscObjectViewFromOptions((PetscObject)dm, obj, name);
917: return 0;
918: }
920: /*@C
921: DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
922: save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
924: Collective on dm
926: Input Parameters:
927: + dm - the `DM` object to view
928: - v - the viewer
930: Notes:
931: Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` one can save multiple `DMPLEX`
932: meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
933: before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
935: Level: beginner
937: .seealso: `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat`(), `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
939: @*/
940: PetscErrorCode DMView(DM dm, PetscViewer v)
941: {
942: PetscBool isbinary;
943: PetscMPIInt size;
944: PetscViewerFormat format;
947: if (!v) PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v);
949: /* Ideally, we would like to have this test on.
950: However, it currently breaks socket viz via GLVis.
951: During DMView(parallel_mesh,glvis_viewer), each
952: process opens a sequential ASCII socket to visualize
953: the local mesh, and PetscObjectView(dm,local_socket)
954: is internally called inside VecView_GLVis, incurring
955: in an error here */
957: PetscViewerCheckWritable(v);
959: PetscViewerGetFormat(v, &format);
960: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
961: if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return 0;
962: PetscObjectPrintClassNamePrefixType((PetscObject)dm, v);
963: PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary);
964: if (isbinary) {
965: PetscInt classid = DM_FILE_CLASSID;
966: char type[256];
968: PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT);
969: PetscStrncpy(type, ((PetscObject)dm)->type_name, 256);
970: PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR);
971: }
972: PetscTryTypeMethod(dm, view, v);
973: return 0;
974: }
976: /*@
977: DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
978: that is it has no ghost locations.
980: Collective on dm
982: Input Parameter:
983: . dm - the `DM` object
985: Output Parameter:
986: . vec - the global vector
988: Level: beginner
990: .seealso: `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
991: `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
992: @*/
993: PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
994: {
997: PetscUseTypeMethod(dm, createglobalvector, vec);
998: if (PetscDefined(USE_DEBUG)) {
999: DM vdm;
1001: VecGetDM(*vec, &vdm);
1003: }
1004: return 0;
1005: }
1007: /*@
1008: DMCreateLocalVector - Creates a local vector from a `DM` object.
1010: Not Collective
1012: Input Parameter:
1013: . dm - the `DM` object
1015: Output Parameter:
1016: . vec - the local vector
1018: Level: beginner
1020: Notes:
1021: A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1023: .seealso: `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1024: `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1025: @*/
1026: PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1027: {
1030: PetscUseTypeMethod(dm, createlocalvector, vec);
1031: if (PetscDefined(USE_DEBUG)) {
1032: DM vdm;
1034: VecGetDM(*vec, &vdm);
1036: }
1037: return 0;
1038: }
1040: /*@
1041: DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1043: Collective on dm
1045: Input Parameter:
1046: . dm - the `DM` that provides the mapping
1048: Output Parameter:
1049: . ltog - the mapping
1051: Level: advanced
1053: Notes:
1054: The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1056: Vectors obtained with `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1057: need to use this function with those objects.
1059: This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1061: .seealso: `DMCreateLocalVector()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1062: `DMCreateMatrix()`
1063: @*/
1064: PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1065: {
1066: PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1070: if (!dm->ltogmap) {
1071: PetscSection section, sectionGlobal;
1073: DMGetLocalSection(dm, §ion);
1074: if (section) {
1075: const PetscInt *cdofs;
1076: PetscInt *ltog;
1077: PetscInt pStart, pEnd, n, p, k, l;
1079: DMGetGlobalSection(dm, §ionGlobal);
1080: PetscSectionGetChart(section, &pStart, &pEnd);
1081: PetscSectionGetStorageSize(section, &n);
1082: PetscMalloc1(n, <og); /* We want the local+overlap size */
1083: for (p = pStart, l = 0; p < pEnd; ++p) {
1084: PetscInt bdof, cdof, dof, off, c, cind;
1086: /* Should probably use constrained dofs */
1087: PetscSectionGetDof(section, p, &dof);
1088: PetscSectionGetConstraintDof(section, p, &cdof);
1089: PetscSectionGetConstraintIndices(section, p, &cdofs);
1090: PetscSectionGetOffset(sectionGlobal, p, &off);
1091: /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1092: bdof = cdof && (dof - cdof) ? 1 : dof;
1093: if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1095: for (c = 0, cind = 0; c < dof; ++c, ++l) {
1096: if (cind < cdof && c == cdofs[cind]) {
1097: ltog[l] = off < 0 ? off - c : -(off + c + 1);
1098: cind++;
1099: } else {
1100: ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1101: }
1102: }
1103: }
1104: /* Must have same blocksize on all procs (some might have no points) */
1105: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
1106: bsLocal[1] = bs;
1107: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax);
1108: if (bsMinMax[0] != bsMinMax[1]) {
1109: bs = 1;
1110: } else {
1111: bs = bsMinMax[0];
1112: }
1113: bs = bs < 0 ? 1 : bs;
1114: /* Must reduce indices by blocksize */
1115: if (bs > 1) {
1116: for (l = 0, k = 0; l < n; l += bs, ++k) {
1117: // Integer division of negative values truncates toward zero(!), not toward negative infinity
1118: ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1119: }
1120: n /= bs;
1121: }
1122: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1123: } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1124: }
1125: *ltog = dm->ltogmap;
1126: return 0;
1127: }
1129: /*@
1130: DMGetBlockSize - Gets the inherent block size associated with a `DM`
1132: Not Collective
1134: Input Parameter:
1135: . dm - the `DM` with block structure
1137: Output Parameter:
1138: . bs - the block size, 1 implies no exploitable block structure
1140: Level: intermediate
1142: Note:
1143: This might be the number of degrees of freedom at each grid point for a structured grid.
1145: Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1146: rather different locations in the vectors may have a different block size.
1148: .seealso: `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1149: @*/
1150: PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1151: {
1155: *bs = dm->bs;
1156: return 0;
1157: }
1159: /*@C
1160: DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1161: `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1163: Collective on dmc
1165: Input Parameters:
1166: + dmc - the `DM` object
1167: - dmf - the second, finer `DM` object
1169: Output Parameters:
1170: + mat - the interpolation
1171: - vec - the scaling (optional), see `DMCreateInterpolationScale()`
1173: Level: developer
1175: Notes:
1176: For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1177: DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1179: For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1180: vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1182: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1183: @*/
1184: PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1185: {
1189: PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0);
1190: PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1191: PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0);
1192: return 0;
1193: }
1195: /*@
1196: DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is the transpose of the interpolation between the `DM`.
1197: xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) restriction. In other words xcoarse is the coarse
1198: representation of xfine.
1200: Input Parameters:
1201: + dac - `DM` that defines a coarse mesh
1202: . daf - `DM` that defines a fine mesh
1203: - mat - the restriction (or interpolation operator) from fine to coarse
1205: Output Parameter:
1206: . scale - the scaled vector
1208: Level: advanced
1210: Developer Notes:
1211: If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1212: on the restriction/interpolation operator to set the bindingpropagates flag to true.
1214: .seealso: `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, DMCreateRestriction()`, `DMCreateGlobalVector()`
1215: @*/
1216: PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1217: {
1218: Vec fine;
1219: PetscScalar one = 1.0;
1220: #if defined(PETSC_HAVE_CUDA)
1221: PetscBool bindingpropagates, isbound;
1222: #endif
1224: DMCreateGlobalVector(daf, &fine);
1225: DMCreateGlobalVector(dac, scale);
1226: VecSet(fine, one);
1227: #if defined(PETSC_HAVE_CUDA)
1228: /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1229: * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1230: * we'll need to do it for that case, too.*/
1231: VecGetBindingPropagates(fine, &bindingpropagates);
1232: if (bindingpropagates) {
1233: MatSetBindingPropagates(mat, PETSC_TRUE);
1234: VecBoundToCPU(fine, &isbound);
1235: MatBindToCPU(mat, isbound);
1236: }
1237: #endif
1238: MatRestrict(mat, fine, *scale);
1239: VecDestroy(&fine);
1240: VecReciprocal(*scale);
1241: return 0;
1242: }
1244: /*@
1245: DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1246: `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1248: Collective on dmc
1250: Input Parameters:
1251: + dmc - the `DM` object
1252: - dmf - the second, finer `DM` object
1254: Output Parameter:
1255: . mat - the restriction
1257: Level: developer
1259: Note:
1260: This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1261: matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1263: .seealso: `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1264: @*/
1265: PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1266: {
1270: PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0);
1271: PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1272: PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0);
1273: return 0;
1274: }
1276: /*@
1277: DMCreateInjection - Gets injection matrix between two `DM` objects. This is an operator that applied to a vector obtained with
1278: `DMCreateGlobalVector()` on the fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting the values
1279: on the coarse grid points. This compares to the operator obtained by `DMCreateRestriction()` or the transpose of the operator obtained
1280: by `DMCreateInterpolation()` that uses a "local weighted average" of the values around the coarse grid point as the coarse grid value.
1282: Collective on dac
1284: Input Parameters:
1285: + dac - the `DM` object
1286: - daf - the second, finer `DM` object
1288: Output Parameter:
1289: . mat - the injection
1291: Level: developer
1293: Note:
1294: For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1295: `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1297: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1298: `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1299: @*/
1300: PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1301: {
1305: PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0);
1306: PetscUseTypeMethod(dac, createinjection, daf, mat);
1307: PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0);
1308: return 0;
1309: }
1311: /*@
1312: DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1313: a Galerkin finite element model on the `DM`
1315: Collective on dac
1317: Input Parameters:
1318: + dmc - the target `DM` object
1319: - dmf - the source `DM` object
1321: Output Parameter:
1322: . mat - the mass matrix
1324: Level: developer
1326: Notes:
1327: For `DMPLEX` the finite element model for the `DM` must have been already provided.
1329: if dmc is dmf then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1331: .seealso: `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1332: @*/
1333: PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1334: {
1338: PetscLogEventBegin(DM_CreateMassMatrix, 0, 0, 0, 0);
1339: PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1340: PetscLogEventEnd(DM_CreateMassMatrix, 0, 0, 0, 0);
1341: return 0;
1342: }
1344: /*@
1345: DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1347: Collective on dm
1349: Input Parameter:
1350: . dm - the `DM` object
1352: Output Parameter:
1353: . lm - the lumped mass matrix, which is a diagonal matrix, represented as a vector
1355: Level: developer
1357: Note:
1358: See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1360: .seealso: `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1361: @*/
1362: PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *lm)
1363: {
1366: PetscUseTypeMethod(dm, createmassmatrixlumped, lm);
1367: return 0;
1368: }
1370: /*@
1371: DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1372: of a PDE on the `DM`.
1374: Collective on dm
1376: Input Parameters:
1377: + dm - the `DM` object
1378: - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1380: Output Parameter:
1381: . coloring - the coloring
1383: Notes:
1384: Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1385: matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1387: This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1389: Level: developer
1391: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1392: @*/
1393: PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1394: {
1397: PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1398: return 0;
1399: }
1401: /*@
1402: DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1404: Collective on dm
1406: Input Parameter:
1407: . dm - the `DM` object
1409: Output Parameter:
1410: . mat - the empty Jacobian
1412: Level: beginner
1414: Options Database Keys:
1415: . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1417: Notes:
1418: This properly preallocates the number of nonzeros in the sparse matrix so you
1419: do not need to do it yourself.
1421: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1422: the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1424: For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1425: internally by PETSc.
1427: For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1428: `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1430: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1431: @*/
1432: PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1433: {
1436: MatInitializePackage();
1437: PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0);
1438: PetscUseTypeMethod(dm, creatematrix, mat);
1439: if (PetscDefined(USE_DEBUG)) {
1440: DM mdm;
1442: MatGetDM(*mat, &mdm);
1444: }
1445: /* Handle nullspace and near nullspace */
1446: if (dm->Nf) {
1447: MatNullSpace nullSpace;
1448: PetscInt Nf, f;
1450: DMGetNumFields(dm, &Nf);
1451: for (f = 0; f < Nf; ++f) {
1452: if (dm->nullspaceConstructors[f]) {
1453: (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1454: MatSetNullSpace(*mat, nullSpace);
1455: MatNullSpaceDestroy(&nullSpace);
1456: break;
1457: }
1458: }
1459: for (f = 0; f < Nf; ++f) {
1460: if (dm->nearnullspaceConstructors[f]) {
1461: (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1462: MatSetNearNullSpace(*mat, nullSpace);
1463: MatNullSpaceDestroy(&nullSpace);
1464: }
1465: }
1466: }
1467: PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0);
1468: return 0;
1469: }
1471: /*@
1472: DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and `ISLocalToGlobalMapping` will be
1473: properly set, but the data structures to store values in the matrices will not be preallocated. This is most useful to reduce initialization costs when
1474: `MatSetPreallocationCOO()` and `MatSetValuesCOO()` will be used.
1476: Logically Collective on dm
1478: Input Parameters:
1479: + dm - the `DM`
1480: - skip - `PETSC_TRUE` to skip preallocation
1482: Level: developer
1484: .seealso: `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1485: @*/
1486: PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1487: {
1489: dm->prealloc_skip = skip;
1490: return 0;
1491: }
1493: /*@
1494: DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1495: preallocated but the nonzero structure and zero values will not be set.
1497: Logically Collective on dm
1499: Input Parameters:
1500: + dm - the `DM`
1501: - only - `PETSC_TRUE` if only want preallocation
1503: Level: developer
1505: Options Database Keys:
1506: . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1508: .seealso: `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1509: @*/
1510: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1511: {
1513: dm->prealloc_only = only;
1514: return 0;
1515: }
1517: /*@
1518: DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created
1519: but the array for numerical values will not be allocated.
1521: Logically Collective on dm
1523: Input Parameters:
1524: + dm - the `DM`
1525: - only - `PETSC_TRUE` if you only want matrix structure
1527: Level: developer
1529: .seealso: `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1530: @*/
1531: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1532: {
1534: dm->structure_only = only;
1535: return 0;
1536: }
1538: /*@C
1539: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1541: Not Collective
1543: Input Parameters:
1544: + dm - the `DM` object
1545: . count - The minimum size
1546: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, or MPIU_INT)
1548: Output Parameter:
1549: . array - the work array
1551: Level: developer
1553: Note:
1554: A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1556: The array may contain nonzero values
1558: .seealso: `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1559: @*/
1560: PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1561: {
1562: DMWorkLink link;
1563: PetscMPIInt dsize;
1567: if (dm->workin) {
1568: link = dm->workin;
1569: dm->workin = dm->workin->next;
1570: } else {
1571: PetscNew(&link);
1572: }
1573: MPI_Type_size(dtype, &dsize);
1574: if (((size_t)dsize * count) > link->bytes) {
1575: PetscFree(link->mem);
1576: PetscMalloc(dsize * count, &link->mem);
1577: link->bytes = dsize * count;
1578: }
1579: link->next = dm->workout;
1580: dm->workout = link;
1581: #if defined(__MEMCHECK_H) && (defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin))
1582: VALGRIND_MAKE_MEM_NOACCESS((char *)link->mem + (size_t)dsize * count, link->bytes - (size_t)dsize * count);
1583: VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize * count);
1584: #endif
1585: *(void **)mem = link->mem;
1586: return 0;
1587: }
1589: /*@C
1590: DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1592: Not Collective
1594: Input Parameters:
1595: + dm - the `DM` object
1596: . count - The minimum size
1597: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1599: Output Parameter:
1600: . array - the work array
1602: Level: developer
1604: Developer Notes:
1605: count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1607: .seealso: `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1608: @*/
1609: PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1610: {
1611: DMWorkLink *p, link;
1615: for (p = &dm->workout; (link = *p); p = &link->next) {
1616: if (link->mem == *(void **)mem) {
1617: *p = link->next;
1618: link->next = dm->workin;
1619: dm->workin = link;
1620: *(void **)mem = NULL;
1621: return 0;
1622: }
1623: }
1624: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1625: }
1627: /*@C
1628: DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1629: are joined or split, such as in `DMCreateSubDM()`
1631: Logically collective on dm
1633: Input Parameters:
1634: + dm - The `DM`
1635: . field - The field number for the nullspace
1636: - nullsp - A callback to create the nullspace
1638: Calling sequence of nullsp:
1639: .vb
1640: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1641: .ve
1642: + dm - The present `DM`
1643: . origField - The field number given above, in the original `DM`
1644: . field - The field number in dm
1645: - nullSpace - The nullspace for the given field
1647: Level: intermediate
1649: Fortran Notes:
1650: This function is not available from Fortran.
1652: .seealso: `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1653: @*/
1654: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1655: {
1658: dm->nullspaceConstructors[field] = nullsp;
1659: return 0;
1660: }
1662: /*@C
1663: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`
1665: Not collective
1667: Input Parameters:
1668: + dm - The `DM`
1669: - field - The field number for the nullspace
1671: Output Parameter:
1672: . nullsp - A callback to create the nullspace
1674: Calling sequence of nullsp:
1675: .vb
1676: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1677: .ve
1678: + dm - The present DM
1679: . origField - The field number given above, in the original DM
1680: . field - The field number in dm
1681: - nullSpace - The nullspace for the given field
1683: Fortran Note:
1684: This function is not available from Fortran.
1686: Level: intermediate
1688: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1689: @*/
1690: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1691: {
1695: *nullsp = dm->nullspaceConstructors[field];
1696: return 0;
1697: }
1699: /*@C
1700: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1702: Logically collective on dm
1704: Input Parameters:
1705: + dm - The `DM`
1706: . field - The field number for the nullspace
1707: - nullsp - A callback to create the near-nullspace
1709: Calling sequence of nullsp:
1710: .vb
1711: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1712: .ve
1713: + dm - The present `DM`
1714: . origField - The field number given above, in the original `DM`
1715: . field - The field number in dm
1716: - nullSpace - The nullspace for the given field
1718: Fortran Note:
1719: This function is not available from Fortran.
1721: Level: intermediate
1723: .seealso: `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1724: `MatNullSpace`
1725: @*/
1726: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1727: {
1730: dm->nearnullspaceConstructors[field] = nullsp;
1731: return 0;
1732: }
1734: /*@C
1735: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1737: Not collective
1739: Input Parameters:
1740: + dm - The `DM`
1741: - field - The field number for the nullspace
1743: Output Parameter:
1744: . nullsp - A callback to create the near-nullspace
1746: Calling sequence of nullsp:
1747: .vb
1748: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1749: .ve
1750: + dm - The present `DM`
1751: . origField - The field number given above, in the original `DM`
1752: . field - The field number in dm
1753: - nullSpace - The nullspace for the given field
1755: Fortran Note:
1756: This function is not available from Fortran.
1758: Level: intermediate
1760: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1761: `MatNullSpace`, `DMCreateSuperDM()`
1762: @*/
1763: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1764: {
1768: *nullsp = dm->nearnullspaceConstructors[field];
1769: return 0;
1770: }
1772: /*@C
1773: DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`
1775: Not collective
1777: Input Parameter:
1778: . dm - the `DM` object
1780: Output Parameters:
1781: + numFields - The number of fields (or NULL if not requested)
1782: . fieldNames - The number of each field (or NULL if not requested)
1783: - fields - The global indices for each field (or NULL if not requested)
1785: Level: intermediate
1787: Note:
1788: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1789: `PetscFree()`, every entry of fields should be destroyed with `ISDestroy()`, and both arrays should be freed with
1790: `PetscFree()`.
1792: Fortran Note:
1793: Not available in Fortran.
1795: Developer Note:
1796: It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1797: likely be removed.
1799: .seealso: `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1800: `DMCreateFieldDecomposition()`
1801: @*/
1802: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1803: {
1804: PetscSection section, sectionGlobal;
1807: if (numFields) {
1809: *numFields = 0;
1810: }
1811: if (fieldNames) {
1813: *fieldNames = NULL;
1814: }
1815: if (fields) {
1817: *fields = NULL;
1818: }
1819: DMGetLocalSection(dm, §ion);
1820: if (section) {
1821: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1822: PetscInt nF, f, pStart, pEnd, p;
1824: DMGetGlobalSection(dm, §ionGlobal);
1825: PetscSectionGetNumFields(section, &nF);
1826: PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices);
1827: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1828: for (f = 0; f < nF; ++f) {
1829: fieldSizes[f] = 0;
1830: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1831: }
1832: for (p = pStart; p < pEnd; ++p) {
1833: PetscInt gdof;
1835: PetscSectionGetDof(sectionGlobal, p, &gdof);
1836: if (gdof > 0) {
1837: for (f = 0; f < nF; ++f) {
1838: PetscInt fdof, fcdof, fpdof;
1840: PetscSectionGetFieldDof(section, p, f, &fdof);
1841: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1842: fpdof = fdof - fcdof;
1843: if (fpdof && fpdof != fieldNc[f]) {
1844: /* Layout does not admit a pointwise block size */
1845: fieldNc[f] = 1;
1846: }
1847: fieldSizes[f] += fpdof;
1848: }
1849: }
1850: }
1851: for (f = 0; f < nF; ++f) {
1852: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1853: fieldSizes[f] = 0;
1854: }
1855: for (p = pStart; p < pEnd; ++p) {
1856: PetscInt gdof, goff;
1858: PetscSectionGetDof(sectionGlobal, p, &gdof);
1859: if (gdof > 0) {
1860: PetscSectionGetOffset(sectionGlobal, p, &goff);
1861: for (f = 0; f < nF; ++f) {
1862: PetscInt fdof, fcdof, fc;
1864: PetscSectionGetFieldDof(section, p, f, &fdof);
1865: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1866: for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
1867: }
1868: }
1869: }
1870: if (numFields) *numFields = nF;
1871: if (fieldNames) {
1872: PetscMalloc1(nF, fieldNames);
1873: for (f = 0; f < nF; ++f) {
1874: const char *fieldName;
1876: PetscSectionGetFieldName(section, f, &fieldName);
1877: PetscStrallocpy(fieldName, (char **)&(*fieldNames)[f]);
1878: }
1879: }
1880: if (fields) {
1881: PetscMalloc1(nF, fields);
1882: for (f = 0; f < nF; ++f) {
1883: PetscInt bs, in[2], out[2];
1885: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1886: in[0] = -fieldNc[f];
1887: in[1] = fieldNc[f];
1888: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1889: bs = (-out[0] == out[1]) ? out[1] : 1;
1890: ISSetBlockSize((*fields)[f], bs);
1891: }
1892: }
1893: PetscFree3(fieldSizes, fieldNc, fieldIndices);
1894: } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
1895: return 0;
1896: }
1898: /*@C
1899: DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
1900: corresponding to different fields: each `IS` contains the global indices of the dofs of the
1901: corresponding field, defined by `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
1902: The same as `DMCreateFieldIS()` but also returns a `DM` for each field.
1904: Not collective
1906: Input Parameter:
1907: . dm - the `DM` object
1909: Output Parameters:
1910: + len - The number of fields (or NULL if not requested)
1911: . namelist - The name for each field (or NULL if not requested)
1912: . islist - The global indices for each field (or NULL if not requested)
1913: - dmlist - The `DM`s for each field subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined)
1915: Level: intermediate
1917: Note:
1918: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1919: `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`,
1920: and all of the arrays should be freed with `PetscFree()`.
1922: Fortran Note:
1923: Not available in Fortran.
1925: Developer Note:
1926: It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.
1928: .seealso: `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
1929: @*/
1930: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1931: {
1933: if (len) {
1935: *len = 0;
1936: }
1937: if (namelist) {
1939: *namelist = NULL;
1940: }
1941: if (islist) {
1943: *islist = NULL;
1944: }
1945: if (dmlist) {
1947: *dmlist = NULL;
1948: }
1949: /*
1950: Is it a good idea to apply the following check across all impls?
1951: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1952: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1953: */
1955: if (!dm->ops->createfielddecomposition) {
1956: PetscSection section;
1957: PetscInt numFields, f;
1959: DMGetLocalSection(dm, §ion);
1960: if (section) PetscSectionGetNumFields(section, &numFields);
1961: if (section && numFields && dm->ops->createsubdm) {
1962: if (len) *len = numFields;
1963: if (namelist) PetscMalloc1(numFields, namelist);
1964: if (islist) PetscMalloc1(numFields, islist);
1965: if (dmlist) PetscMalloc1(numFields, dmlist);
1966: for (f = 0; f < numFields; ++f) {
1967: const char *fieldName;
1969: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1970: if (namelist) {
1971: PetscSectionGetFieldName(section, f, &fieldName);
1972: PetscStrallocpy(fieldName, (char **)&(*namelist)[f]);
1973: }
1974: }
1975: } else {
1976: DMCreateFieldIS(dm, len, namelist, islist);
1977: /* By default there are no DMs associated with subproblems. */
1978: if (dmlist) *dmlist = NULL;
1979: }
1980: } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
1981: return 0;
1982: }
1984: /*@C
1985: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1986: The fields are defined by DMCreateFieldIS().
1988: Not collective
1990: Input Parameters:
1991: + dm - The `DM `object
1992: . numFields - The number of fields to select
1993: - fields - The field numbers of the selected fields
1995: Output Parameters:
1996: + is - The global indices for all the degrees of freedom in the new sub `DM`
1997: - subdm - The `DM` for the subproblem
1999: Note:
2000: You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2002: Level: intermediate
2004: .seealso: `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `DM`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2005: @*/
2006: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2007: {
2012: PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2013: return 0;
2014: }
2016: /*@C
2017: DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in.
2019: Not collective
2021: Input Parameters:
2022: + dms - The `DM` objects
2023: - n - The number of `DM`s
2025: Output Parameters:
2026: + is - The global indices for each of subproblem within the super `DM`, or NULL
2027: - superdm - The `DM` for the superproblem
2029: Note:
2030: You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2032: Level: intermediate
2034: .seealso: `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2035: @*/
2036: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS **is, DM *superdm)
2037: {
2038: PetscInt i;
2045: if (n) {
2046: DM dm = dms[0];
2047: (*dm->ops->createsuperdm)(dms, n, is, superdm);
2048: }
2049: return 0;
2050: }
2052: /*@C
2053: DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a problem into subproblems
2054: corresponding to restrictions to pairs of nested subdomains: each `IS` contains the global
2055: indices of the dofs of the corresponding subdomains with in the dofs of the original `DM`.
2056: The inner subdomains conceptually define a nonoverlapping covering, while outer subdomains can overlap.
2057: The optional list of `DM`s define a `DM` for each subproblem.
2059: Not collective
2061: Input Parameter:
2062: . dm - the `DM` object
2064: Output Parameters:
2065: + n - The number of subproblems in the domain decomposition (or NULL if not requested)
2066: . namelist - The name for each subdomain (or NULL if not requested)
2067: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2068: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2069: - dmlist - The `DM`s for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined)
2071: Level: intermediate
2073: Note:
2074: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
2075: `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`,
2076: and all of the arrays should be freed with `PetscFree()`.
2078: Questions:
2079: The dmlist is for the inner subdomains or the outer subdomains or all subdomains?
2081: .seealso: `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldDecomposition()`
2082: @*/
2083: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2084: {
2085: DMSubDomainHookLink link;
2086: PetscInt i, l;
2089: if (n) {
2091: *n = 0;
2092: }
2093: if (namelist) {
2095: *namelist = NULL;
2096: }
2097: if (innerislist) {
2099: *innerislist = NULL;
2100: }
2101: if (outerislist) {
2103: *outerislist = NULL;
2104: }
2105: if (dmlist) {
2107: *dmlist = NULL;
2108: }
2109: /*
2110: Is it a good idea to apply the following check across all impls?
2111: Perhaps some impls can have a well-defined decomposition before DMSetUp?
2112: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2113: */
2115: if (dm->ops->createdomaindecomposition) {
2116: PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2117: /* copy subdomain hooks and context over to the subdomain DMs */
2118: if (dmlist && *dmlist) {
2119: for (i = 0; i < l; i++) {
2120: for (link = dm->subdomainhook; link; link = link->next) {
2121: if (link->ddhook) (*link->ddhook)(dm, (*dmlist)[i], link->ctx);
2122: }
2123: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2124: }
2125: }
2126: if (n) *n = l;
2127: }
2128: return 0;
2129: }
2131: /*@C
2132: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
2134: Not collective
2136: Input Parameters:
2137: + dm - the `DM` object
2138: . n - the number of subdomain scatters
2139: - subdms - the local subdomains
2141: Output Parameters:
2142: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2143: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2144: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2146: Note:
2147: This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2148: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2149: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2150: solution and residual data.
2152: Questions:
2153: Can the subdms input be anything or are they exactly the `DM` obtained from `DMCreateDomainDecomposition()`?
2155: Level: developer
2157: .seealso: `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2158: @*/
2159: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **gscat)
2160: {
2163: PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2164: return 0;
2165: }
2167: /*@
2168: DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh
2170: Collective on dm
2172: Input Parameters:
2173: + dm - the `DM` object
2174: - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
2176: Output Parameter:
2177: . dmf - the refined `D`M, or NULL
2179: Options Database Keys:
2180: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2182: Note:
2183: If no refinement was done, the return value is NULL
2185: Level: developer
2187: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2188: @*/
2189: PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2190: {
2191: DMRefineHookLink link;
2194: PetscLogEventBegin(DM_Refine, dm, 0, 0, 0);
2195: PetscUseTypeMethod(dm, refine, comm, dmf);
2196: if (*dmf) {
2197: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2199: PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf);
2201: (*dmf)->ctx = dm->ctx;
2202: (*dmf)->leveldown = dm->leveldown;
2203: (*dmf)->levelup = dm->levelup + 1;
2205: DMSetMatType(*dmf, dm->mattype);
2206: for (link = dm->refinehook; link; link = link->next) {
2207: if (link->refinehook) (*link->refinehook)(dm, *dmf, link->ctx);
2208: }
2209: }
2210: PetscLogEventEnd(DM_Refine, dm, 0, 0, 0);
2211: return 0;
2212: }
2214: /*@C
2215: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2217: Logically Collective on coarse
2219: Input Parameters:
2220: + coarse - `DM` on which to run a hook when interpolating to a finer level
2221: . refinehook - function to run when setting up the finer level
2222: . interphook - function to run to update data on finer levels (once per `SNESSolve`())
2223: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2225: Calling sequence of refinehook:
2226: $ refinehook(DM coarse,DM fine,void *ctx);
2228: + coarse - coarse level `DM`
2229: . fine - fine level `DM` to interpolate problem to
2230: - ctx - optional user-defined function context
2232: Calling sequence for interphook:
2233: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2235: + coarse - coarse level `DM`
2236: . interp - matrix interpolating a coarse-level solution to the finer grid
2237: . fine - fine level `DM` to update
2238: - ctx - optional user-defined function context
2240: Level: advanced
2242: Notes:
2243: This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2244: passed to fine grids while grid sequencing.
2246: The actual interpolation is done when `DMInterpolate()` is called.
2248: If this function is called multiple times, the hooks will be run in the order they are added.
2250: Fortran Note:
2251: This function is not available from Fortran.
2253: .seealso: `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2254: @*/
2255: PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2256: {
2257: DMRefineHookLink link, *p;
2260: for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2261: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return 0;
2262: }
2263: PetscNew(&link);
2264: link->refinehook = refinehook;
2265: link->interphook = interphook;
2266: link->ctx = ctx;
2267: link->next = NULL;
2268: *p = link;
2269: return 0;
2270: }
2272: /*@C
2273: DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2274: a nonlinear problem to a finer grid
2276: Logically Collective on coarse
2278: Input Parameters:
2279: + coarse - the `DM` on which to run a hook when restricting to a coarser level
2280: . refinehook - function to run when setting up a finer level
2281: . interphook - function to run to update data on finer levels
2282: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2284: Level: advanced
2286: Note:
2287: This function does nothing if the hook is not in the list.
2289: Fortran Note:
2290: This function is not available from Fortran.
2292: .seealso: `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2293: @*/
2294: PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2295: {
2296: DMRefineHookLink link, *p;
2299: for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2300: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2301: link = *p;
2302: *p = link->next;
2303: PetscFree(link);
2304: break;
2305: }
2306: }
2307: return 0;
2308: }
2310: /*@
2311: DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`
2313: Collective if any hooks are
2315: Input Parameters:
2316: + coarse - coarser `DM` to use as a base
2317: . interp - interpolation matrix, apply using `MatInterpolate()`
2318: - fine - finer `DM` to update
2320: Level: developer
2322: Developer Note:
2323: This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2324: an API with consistent terminology.
2326: .seealso: `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2327: @*/
2328: PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2329: {
2330: DMRefineHookLink link;
2332: for (link = fine->refinehook; link; link = link->next) {
2333: if (link->interphook) (*link->interphook)(coarse, interp, fine, link->ctx);
2334: }
2335: return 0;
2336: }
2338: /*@
2339: DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2341: Collective on dm
2343: Input Parameters:
2344: + coarse - coarse `DM`
2345: . fine - fine `DM`
2346: . interp - (optional) the matrix computed by `DMCreateInterpolation()`. Implementations may not need this, but if it
2347: is available it can avoid some recomputation. If it is provided, `MatInterpolate()` will be used if
2348: the coarse `DM` does not have a specialized implementation.
2349: - coarseSol - solution on the coarse mesh
2351: Output Parameter:
2352: . fineSol - the interpolation of coarseSol to the fine mesh
2354: Level: developer
2356: Note:
2357: This function exists because the interpolation of a solution vector between meshes is not always a linear
2358: map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2359: out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2360: slope-limiting reconstruction.
2362: Developer Note:
2363: This doesn't just interpolate "solutions" so its API name is questionable.
2365: .seealso: `DMInterpolate()`, `DMCreateInterpolation()`
2366: @*/
2367: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2368: {
2369: PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;
2376: PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol);
2377: if (interpsol) {
2378: (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2379: } else if (interp) {
2380: MatInterpolate(interp, coarseSol, fineSol);
2381: } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2382: return 0;
2383: }
2385: /*@
2386: DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.
2388: Not Collective
2390: Input Parameter:
2391: . dm - the `DM` object
2393: Output Parameter:
2394: . level - number of refinements
2396: Level: developer
2398: Note:
2399: This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.
2401: .seealso: `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2402: @*/
2403: PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2404: {
2406: *level = dm->levelup;
2407: return 0;
2408: }
2410: /*@
2411: DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.
2413: Not Collective
2415: Input Parameters:
2416: + dm - the `DM` object
2417: - level - number of refinements
2419: Level: advanced
2421: Notes:
2422: This value is used by `PCMG` to determine how many multigrid levels to use
2424: The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.
2426: .seealso: `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2427: @*/
2428: PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2429: {
2431: dm->levelup = level;
2432: return 0;
2433: }
2435: /*@
2436: DMExtrude - Extrude a `DM` object from a surface
2438: Collective on dm
2440: Input Parameters:
2441: + dm - the `DM` object
2442: - layers - the number of extruded cell layers
2444: Output Parameter:
2445: . dme - the extruded `DM`, or NULL
2447: Note:
2448: If no extrusion was done, the return value is NULL
2450: Level: developer
2452: .seealso: `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2453: @*/
2454: PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2455: {
2457: PetscUseTypeMethod(dm, extrude, layers, dme);
2458: if (*dme) {
2459: (*dme)->ops->creatematrix = dm->ops->creatematrix;
2460: PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme);
2461: (*dme)->ctx = dm->ctx;
2462: DMSetMatType(*dme, dm->mattype);
2463: }
2464: return 0;
2465: }
2467: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2468: {
2471: *tdm = dm->transformDM;
2472: return 0;
2473: }
2475: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2476: {
2479: *tv = dm->transform;
2480: return 0;
2481: }
2483: /*@
2484: DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors
2486: Input Parameter:
2487: . dm - The DM
2489: Output Parameter:
2490: . flg - PETSC_TRUE if a basis transformation should be done
2492: Level: developer
2494: .seealso: `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2495: @*/
2496: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2497: {
2498: Vec tv;
2502: DMGetBasisTransformVec_Internal(dm, &tv);
2503: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2504: return 0;
2505: }
2507: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2508: {
2509: PetscSection s, ts;
2510: PetscScalar *ta;
2511: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2513: DMGetCoordinateDim(dm, &cdim);
2514: DMGetLocalSection(dm, &s);
2515: PetscSectionGetChart(s, &pStart, &pEnd);
2516: PetscSectionGetNumFields(s, &Nf);
2517: DMClone(dm, &dm->transformDM);
2518: DMGetLocalSection(dm->transformDM, &ts);
2519: PetscSectionSetNumFields(ts, Nf);
2520: PetscSectionSetChart(ts, pStart, pEnd);
2521: for (f = 0; f < Nf; ++f) {
2522: PetscSectionGetFieldComponents(s, f, &Nc);
2523: /* We could start to label fields by their transformation properties */
2524: if (Nc != cdim) continue;
2525: for (p = pStart; p < pEnd; ++p) {
2526: PetscSectionGetFieldDof(s, p, f, &dof);
2527: if (!dof) continue;
2528: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2529: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2530: }
2531: }
2532: PetscSectionSetUp(ts);
2533: DMCreateLocalVector(dm->transformDM, &dm->transform);
2534: VecGetArray(dm->transform, &ta);
2535: for (p = pStart; p < pEnd; ++p) {
2536: for (f = 0; f < Nf; ++f) {
2537: PetscSectionGetFieldDof(ts, p, f, &dof);
2538: if (dof) {
2539: PetscReal x[3] = {0.0, 0.0, 0.0};
2540: PetscScalar *tva;
2541: const PetscScalar *A;
2543: /* TODO Get quadrature point for this dual basis vector for coordinate */
2544: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2545: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva);
2546: PetscArraycpy(tva, A, PetscSqr(cdim));
2547: }
2548: }
2549: }
2550: VecRestoreArray(dm->transform, &ta);
2551: return 0;
2552: }
2554: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2555: {
2558: newdm->transformCtx = dm->transformCtx;
2559: newdm->transformSetUp = dm->transformSetUp;
2560: newdm->transformDestroy = NULL;
2561: newdm->transformGetMatrix = dm->transformGetMatrix;
2562: if (newdm->transformSetUp) DMConstructBasisTransform_Internal(newdm);
2563: return 0;
2564: }
2566: /*@C
2567: DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called
2569: Logically Collective on dm
2571: Input Parameters:
2572: + dm - the `DM`
2573: . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2574: . endhook - function to run after `DMGlobalToLocalEnd()` has completed
2575: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2577: Calling sequence for beginhook:
2578: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2580: + dm - global DM
2581: . g - global vector
2582: . mode - mode
2583: . l - local vector
2584: - ctx - optional user-defined function context
2586: Calling sequence for endhook:
2587: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2589: + global - global DM
2590: - ctx - optional user-defined function context
2592: Level: advanced
2594: Note:
2595: The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.
2597: .seealso: `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2598: @*/
2599: PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx)
2600: {
2601: DMGlobalToLocalHookLink link, *p;
2604: for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2605: PetscNew(&link);
2606: link->beginhook = beginhook;
2607: link->endhook = endhook;
2608: link->ctx = ctx;
2609: link->next = NULL;
2610: *p = link;
2611: return 0;
2612: }
2614: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2615: {
2616: Mat cMat;
2617: Vec cVec, cBias;
2618: PetscSection section, cSec;
2619: PetscInt pStart, pEnd, p, dof;
2622: DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias);
2623: if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2624: PetscInt nRows;
2626: MatGetSize(cMat, &nRows, NULL);
2627: if (nRows <= 0) return 0;
2628: DMGetLocalSection(dm, §ion);
2629: MatCreateVecs(cMat, NULL, &cVec);
2630: MatMult(cMat, l, cVec);
2631: if (cBias) VecAXPY(cVec, 1., cBias);
2632: PetscSectionGetChart(cSec, &pStart, &pEnd);
2633: for (p = pStart; p < pEnd; p++) {
2634: PetscSectionGetDof(cSec, p, &dof);
2635: if (dof) {
2636: PetscScalar *vals;
2637: VecGetValuesSection(cVec, cSec, p, &vals);
2638: VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES);
2639: }
2640: }
2641: VecDestroy(&cVec);
2642: }
2643: return 0;
2644: }
2646: /*@
2647: DMGlobalToLocal - update local vectors from global vector
2649: Neighbor-wise Collective on dm
2651: Input Parameters:
2652: + dm - the `DM` object
2653: . g - the global vector
2654: . mode - `INSERT_VALUES` or `ADD_VALUES`
2655: - l - the local vector
2657: Notes:
2658: The communication involved in this update can be overlapped with computation by instead using
2659: `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.
2661: `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2663: Level: beginner
2665: .seealso: `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2666: `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`,
2667: `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2668: @*/
2669: PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2670: {
2671: DMGlobalToLocalBegin(dm, g, mode, l);
2672: DMGlobalToLocalEnd(dm, g, mode, l);
2673: return 0;
2674: }
2676: /*@
2677: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2679: Neighbor-wise Collective on dm
2681: Input Parameters:
2682: + dm - the `DM` object
2683: . g - the global vector
2684: . mode - `INSERT_VALUES` or `ADD_VALUES`
2685: - l - the local vector
2687: Level: intermediate
2689: Notes:
2690: The operation is completed with `DMGlobalToLocalEnd()`
2692: One can perform local computations between the `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` to overlap communication and computation
2694: `DMGlobalToLocal()` is a short form of `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`
2696: `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2698: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`
2699: @*/
2700: PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2701: {
2702: PetscSF sf;
2703: DMGlobalToLocalHookLink link;
2706: for (link = dm->gtolhook; link; link = link->next) {
2707: if (link->beginhook) (*link->beginhook)(dm, g, mode, l, link->ctx);
2708: }
2709: DMGetSectionSF(dm, &sf);
2710: if (sf) {
2711: const PetscScalar *gArray;
2712: PetscScalar *lArray;
2713: PetscMemType lmtype, gmtype;
2716: VecGetArrayAndMemType(l, &lArray, &lmtype);
2717: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2718: PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2719: VecRestoreArrayAndMemType(l, &lArray);
2720: VecRestoreArrayReadAndMemType(g, &gArray);
2721: } else {
2722: (*dm->ops->globaltolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2723: }
2724: return 0;
2725: }
2727: /*@
2728: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2730: Neighbor-wise Collective on dm
2732: Input Parameters:
2733: + dm - the `DM` object
2734: . g - the global vector
2735: . mode - `INSERT_VALUES` or `ADD_VALUES`
2736: - l - the local vector
2738: Level: intermediate
2740: Note:
2741: See `DMGlobalToLocalBegin()` for details.
2743: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`
2744: @*/
2745: PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2746: {
2747: PetscSF sf;
2748: const PetscScalar *gArray;
2749: PetscScalar *lArray;
2750: PetscBool transform;
2751: DMGlobalToLocalHookLink link;
2752: PetscMemType lmtype, gmtype;
2755: DMGetSectionSF(dm, &sf);
2756: DMHasBasisTransform(dm, &transform);
2757: if (sf) {
2760: VecGetArrayAndMemType(l, &lArray, &lmtype);
2761: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2762: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE);
2763: VecRestoreArrayAndMemType(l, &lArray);
2764: VecRestoreArrayReadAndMemType(g, &gArray);
2765: if (transform) DMPlexGlobalToLocalBasis(dm, l);
2766: } else {
2767: (*dm->ops->globaltolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2768: }
2769: DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL);
2770: for (link = dm->gtolhook; link; link = link->next) {
2771: if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
2772: }
2773: return 0;
2774: }
2776: /*@C
2777: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2779: Logically Collective on dm
2781: Input Parameters:
2782: + dm - the `DM`
2783: . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2784: . endhook - function to run after `DMLocalToGlobalEnd()` has completed
2785: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2787: Calling sequence for beginhook:
2788: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2790: + dm - global `DM`
2791: . l - local vector
2792: . mode - mode
2793: . g - global vector
2794: - ctx - optional user-defined function context
2796: Calling sequence for endhook:
2797: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2799: + global - global `DM`
2800: . l - local vector
2801: . mode - mode
2802: . g - global vector
2803: - ctx - optional user-defined function context
2805: Level: advanced
2807: .seealso: `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2808: @*/
2809: PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx)
2810: {
2811: DMLocalToGlobalHookLink link, *p;
2814: for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2815: PetscNew(&link);
2816: link->beginhook = beginhook;
2817: link->endhook = endhook;
2818: link->ctx = ctx;
2819: link->next = NULL;
2820: *p = link;
2821: return 0;
2822: }
2824: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2825: {
2826: Mat cMat;
2827: Vec cVec;
2828: PetscSection section, cSec;
2829: PetscInt pStart, pEnd, p, dof;
2832: DMGetDefaultConstraints(dm, &cSec, &cMat, NULL);
2833: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2834: PetscInt nRows;
2836: MatGetSize(cMat, &nRows, NULL);
2837: if (nRows <= 0) return 0;
2838: DMGetLocalSection(dm, §ion);
2839: MatCreateVecs(cMat, NULL, &cVec);
2840: PetscSectionGetChart(cSec, &pStart, &pEnd);
2841: for (p = pStart; p < pEnd; p++) {
2842: PetscSectionGetDof(cSec, p, &dof);
2843: if (dof) {
2844: PetscInt d;
2845: PetscScalar *vals;
2846: VecGetValuesSection(l, section, p, &vals);
2847: VecSetValuesSection(cVec, cSec, p, vals, mode);
2848: /* for this to be the true transpose, we have to zero the values that
2849: * we just extracted */
2850: for (d = 0; d < dof; d++) vals[d] = 0.;
2851: }
2852: }
2853: MatMultTransposeAdd(cMat, cVec, l, l);
2854: VecDestroy(&cVec);
2855: }
2856: return 0;
2857: }
2858: /*@
2859: DMLocalToGlobal - updates global vectors from local vectors
2861: Neighbor-wise Collective on dm
2863: Input Parameters:
2864: + dm - the `DM` object
2865: . l - the local vector
2866: . 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.
2867: - g - the global vector
2869: Notes:
2870: The communication involved in this update can be overlapped with computation by using
2871: `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.
2873: In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
2875: `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.
2877: Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process
2879: Level: beginner
2881: .seealso: `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()`
2882: @*/
2883: PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
2884: {
2885: DMLocalToGlobalBegin(dm, l, mode, g);
2886: DMLocalToGlobalEnd(dm, l, mode, g);
2887: return 0;
2888: }
2890: /*@
2891: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2893: Neighbor-wise Collective on dm
2895: Input Parameters:
2896: + dm - the `DM` object
2897: . l - the local vector
2898: . 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.
2899: - g - the global vector
2901: Notes:
2902: In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
2904: `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.
2906: Use `DMLocalToGlobalEnd()` to complete the communication process.
2908: `DMLocalToGlobal()` is a short form of `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`
2910: `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.
2912: Level: intermediate
2914: .seealso: `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
2915: @*/
2916: PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
2917: {
2918: PetscSF sf;
2919: PetscSection s, gs;
2920: DMLocalToGlobalHookLink link;
2921: Vec tmpl;
2922: const PetscScalar *lArray;
2923: PetscScalar *gArray;
2924: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2925: PetscMemType lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;
2928: for (link = dm->ltoghook; link; link = link->next) {
2929: if (link->beginhook) (*link->beginhook)(dm, l, mode, g, link->ctx);
2930: }
2931: DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL);
2932: DMGetSectionSF(dm, &sf);
2933: DMGetLocalSection(dm, &s);
2934: switch (mode) {
2935: case INSERT_VALUES:
2936: case INSERT_ALL_VALUES:
2937: case INSERT_BC_VALUES:
2938: isInsert = PETSC_TRUE;
2939: break;
2940: case ADD_VALUES:
2941: case ADD_ALL_VALUES:
2942: case ADD_BC_VALUES:
2943: isInsert = PETSC_FALSE;
2944: break;
2945: default:
2946: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
2947: }
2948: if ((sf && !isInsert) || (s && isInsert)) {
2949: DMHasBasisTransform(dm, &transform);
2950: if (transform) {
2951: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2952: VecCopy(l, tmpl);
2953: DMPlexLocalToGlobalBasis(dm, tmpl);
2954: VecGetArrayRead(tmpl, &lArray);
2955: } else if (isInsert) {
2956: VecGetArrayRead(l, &lArray);
2957: } else {
2958: VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2959: l_inplace = PETSC_TRUE;
2960: }
2961: if (s && isInsert) {
2962: VecGetArray(g, &gArray);
2963: } else {
2964: VecGetArrayAndMemType(g, &gArray, &gmtype);
2965: g_inplace = PETSC_TRUE;
2966: }
2967: if (sf && !isInsert) {
2968: PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2969: } else if (s && isInsert) {
2970: PetscInt gStart, pStart, pEnd, p;
2972: DMGetGlobalSection(dm, &gs);
2973: PetscSectionGetChart(s, &pStart, &pEnd);
2974: VecGetOwnershipRange(g, &gStart, NULL);
2975: for (p = pStart; p < pEnd; ++p) {
2976: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2978: PetscSectionGetDof(s, p, &dof);
2979: PetscSectionGetDof(gs, p, &gdof);
2980: PetscSectionGetConstraintDof(s, p, &cdof);
2981: PetscSectionGetConstraintDof(gs, p, &gcdof);
2982: PetscSectionGetOffset(s, p, &off);
2983: PetscSectionGetOffset(gs, p, &goff);
2984: /* Ignore off-process data and points with no global data */
2985: if (!gdof || goff < 0) continue;
2987: /* If no constraints are enforced in the global vector */
2988: if (!gcdof) {
2989: for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
2990: /* If constraints are enforced in the global vector */
2991: } else if (cdof == gcdof) {
2992: const PetscInt *cdofs;
2993: PetscInt cind = 0;
2995: PetscSectionGetConstraintIndices(s, p, &cdofs);
2996: for (d = 0, e = 0; d < dof; ++d) {
2997: if ((cind < cdof) && (d == cdofs[cind])) {
2998: ++cind;
2999: continue;
3000: }
3001: gArray[goff - gStart + e++] = lArray[off + d];
3002: }
3003: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3004: }
3005: }
3006: if (g_inplace) {
3007: VecRestoreArrayAndMemType(g, &gArray);
3008: } else {
3009: VecRestoreArray(g, &gArray);
3010: }
3011: if (transform) {
3012: VecRestoreArrayRead(tmpl, &lArray);
3013: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3014: } else if (l_inplace) {
3015: VecRestoreArrayReadAndMemType(l, &lArray);
3016: } else {
3017: VecRestoreArrayRead(l, &lArray);
3018: }
3019: } else {
3020: (*dm->ops->localtoglobalbegin)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3021: }
3022: return 0;
3023: }
3025: /*@
3026: DMLocalToGlobalEnd - updates global vectors from local vectors
3028: Neighbor-wise Collective on dm
3030: Input Parameters:
3031: + dm - the `DM` object
3032: . l - the local vector
3033: . mode - `INSERT_VALUES` or `ADD_VALUES`
3034: - g - the global vector
3036: Level: intermediate
3038: Note:
3039: See `DMLocalToGlobalBegin()` for full details
3041: .seealso: `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalEnd()`
3042: @*/
3043: PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3044: {
3045: PetscSF sf;
3046: PetscSection s;
3047: DMLocalToGlobalHookLink link;
3048: PetscBool isInsert, transform;
3051: DMGetSectionSF(dm, &sf);
3052: DMGetLocalSection(dm, &s);
3053: switch (mode) {
3054: case INSERT_VALUES:
3055: case INSERT_ALL_VALUES:
3056: isInsert = PETSC_TRUE;
3057: break;
3058: case ADD_VALUES:
3059: case ADD_ALL_VALUES:
3060: isInsert = PETSC_FALSE;
3061: break;
3062: default:
3063: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3064: }
3065: if (sf && !isInsert) {
3066: const PetscScalar *lArray;
3067: PetscScalar *gArray;
3068: Vec tmpl;
3070: DMHasBasisTransform(dm, &transform);
3071: if (transform) {
3072: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3073: VecGetArrayRead(tmpl, &lArray);
3074: } else {
3075: VecGetArrayReadAndMemType(l, &lArray, NULL);
3076: }
3077: VecGetArrayAndMemType(g, &gArray, NULL);
3078: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
3079: if (transform) {
3080: VecRestoreArrayRead(tmpl, &lArray);
3081: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3082: } else {
3083: VecRestoreArrayReadAndMemType(l, &lArray);
3084: }
3085: VecRestoreArrayAndMemType(g, &gArray);
3086: } else if (s && isInsert) {
3087: } else {
3088: (*dm->ops->localtoglobalend)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3089: }
3090: for (link = dm->ltoghook; link; link = link->next) {
3091: if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
3092: }
3093: return 0;
3094: }
3096: /*@
3097: DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include ghost points
3098: that contain irrelevant values) to another local vector where the ghost
3099: points in the second are set correctly from values on other MPI ranks. Must be followed by `DMLocalToLocalEnd()`.
3101: Neighbor-wise Collective on dm
3103: Input Parameters:
3104: + dm - the `DM` object
3105: . g - the original local vector
3106: - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3108: Output Parameter:
3109: . l - the local vector with correct ghost values
3111: Level: intermediate
3113: .seealso: `DMLocalToLocalEnd(), `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalEnd()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3114: @*/
3115: PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3116: {
3118: (*dm->ops->localtolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3119: return 0;
3120: }
3122: /*@
3123: DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3124: points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3126: Neighbor-wise Collective on dm
3128: Input Parameters:
3129: + da - the `DM` object
3130: . g - the original local vector
3131: - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3133: Output Parameter:
3134: . l - the local vector with correct ghost values
3136: Level: intermediate
3138: .seealso: `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalBegin()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3139: @*/
3140: PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3141: {
3143: (*dm->ops->localtolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3144: return 0;
3145: }
3147: /*@
3148: DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3150: Collective on dm
3152: Input Parameters:
3153: + dm - the `DM` object
3154: - comm - the communicator to contain the new `DM` object (or MPI_COMM_NULL)
3156: Output Parameter:
3157: . dmc - the coarsened `DM`
3159: Level: developer
3161: .seealso: `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3162: @*/
3163: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3164: {
3165: DMCoarsenHookLink link;
3168: PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0);
3169: PetscUseTypeMethod(dm, coarsen, comm, dmc);
3170: if (*dmc) {
3171: (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3172: DMSetCoarseDM(dm, *dmc);
3173: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3174: PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc);
3175: (*dmc)->ctx = dm->ctx;
3176: (*dmc)->levelup = dm->levelup;
3177: (*dmc)->leveldown = dm->leveldown + 1;
3178: DMSetMatType(*dmc, dm->mattype);
3179: for (link = dm->coarsenhook; link; link = link->next) {
3180: if (link->coarsenhook) (*link->coarsenhook)(dm, *dmc, link->ctx);
3181: }
3182: }
3183: PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0);
3185: return 0;
3186: }
3188: /*@C
3189: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3191: Logically Collective on fine
3193: Input Parameters:
3194: + fine - `DM` on which to run a hook when restricting to a coarser level
3195: . coarsenhook - function to run when setting up a coarser level
3196: . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3197: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3199: Calling sequence of coarsenhook:
3200: $ coarsenhook(DM fine,DM coarse,void *ctx);
3202: + fine - fine level `DM`
3203: . coarse - coarse level `DM` to restrict problem to
3204: - ctx - optional user-defined function context
3206: Calling sequence for restricthook:
3207: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3208: $
3209: + fine - fine level `DM`
3210: . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3211: . rscale - scaling vector for restriction
3212: . inject - matrix restricting by injection
3213: . coarse - coarse level DM to update
3214: - ctx - optional user-defined function context
3216: Level: advanced
3218: Notes:
3219: This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.
3221: If this function is called multiple times, the hooks will be run in the order they are added.
3223: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3224: extract the finest level information from its context (instead of from the `SNES`).
3226: The hooks are automatically called by `DMRestrict()`
3228: Fortran Note:
3229: This function is not available from Fortran.
3231: .seealso: `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3232: @*/
3233: PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3234: {
3235: DMCoarsenHookLink link, *p;
3238: for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3239: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3240: }
3241: PetscNew(&link);
3242: link->coarsenhook = coarsenhook;
3243: link->restricthook = restricthook;
3244: link->ctx = ctx;
3245: link->next = NULL;
3246: *p = link;
3247: return 0;
3248: }
3250: /*@C
3251: DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3253: Logically Collective on fine
3255: Input Parameters:
3256: + fine - `DM` on which to run a hook when restricting to a coarser level
3257: . coarsenhook - function to run when setting up a coarser level
3258: . restricthook - function to run to update data on coarser levels
3259: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3261: Level: advanced
3263: Note:
3264: This function does nothing if the hook is not in the list.
3266: Fortran Note:
3267: This function is not available from Fortran.
3269: .seealso: `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3270: @*/
3271: PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3272: {
3273: DMCoarsenHookLink link, *p;
3276: for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3277: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3278: link = *p;
3279: *p = link->next;
3280: PetscFree(link);
3281: break;
3282: }
3283: }
3284: return 0;
3285: }
3287: /*@
3288: DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3290: Collective if any hooks are
3292: Input Parameters:
3293: + fine - finer `DM` from which the data is obtained
3294: . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3295: . rscale - scaling vector for restriction
3296: . inject - injection matrix, also use `MatRestrict()`
3297: - coarse - coarser DM to update
3299: Level: developer
3301: Developer Note:
3302: Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3304: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3305: @*/
3306: PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3307: {
3308: DMCoarsenHookLink link;
3310: for (link = fine->coarsenhook; link; link = link->next) {
3311: if (link->restricthook) (*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx);
3312: }
3313: return 0;
3314: }
3316: /*@C
3317: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3319: Logically Collective on global
3321: Input Parameters:
3322: + global - global `DM`
3323: . ddhook - function to run to pass data to the decomposition `DM` upon its creation
3324: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3325: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3327: Calling sequence for ddhook:
3328: $ ddhook(DM global,DM block,void *ctx)
3330: + global - global `DM`
3331: . block - block `DM`
3332: - ctx - optional user-defined function context
3334: Calling sequence for restricthook:
3335: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3337: + global - global `DM`
3338: . out - scatter to the outer (with ghost and overlap points) block vector
3339: . in - scatter to block vector values only owned locally
3340: . block - block `DM`
3341: - ctx - optional user-defined function context
3343: Level: advanced
3345: Notes:
3346: This function is only needed if auxiliary data needs to be set up on subdomain `DM`s.
3348: If this function is called multiple times, the hooks will be run in the order they are added.
3350: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3351: extract the global information from its context (instead of from the `SNES`).
3353: Fortran Note:
3354: This function is not available from Fortran.
3356: .seealso: `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3357: @*/
3358: PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3359: {
3360: DMSubDomainHookLink link, *p;
3363: for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3364: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3365: }
3366: PetscNew(&link);
3367: link->restricthook = restricthook;
3368: link->ddhook = ddhook;
3369: link->ctx = ctx;
3370: link->next = NULL;
3371: *p = link;
3372: return 0;
3373: }
3375: /*@C
3376: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3378: Logically Collective on global
3380: Input Parameters:
3381: + global - global `DM`
3382: . ddhook - function to run to pass data to the decomposition `DM` upon its creation
3383: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3384: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3386: Level: advanced
3388: Fortran Note:
3389: This function is not available from Fortran.
3391: .seealso: `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3392: @*/
3393: PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3394: {
3395: DMSubDomainHookLink link, *p;
3398: for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3399: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3400: link = *p;
3401: *p = link->next;
3402: PetscFree(link);
3403: break;
3404: }
3405: }
3406: return 0;
3407: }
3409: /*@
3410: DMSubDomainRestrict - restricts user-defined problem data to a block `DM` by running hooks registered by `DMSubDomainHookAdd()`
3412: Collective if any hooks are
3414: Input Parameters:
3415: + fine - finer `DM` to use as a base
3416: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3417: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3418: - coarse - coarser `DM` to update
3420: Level: developer
3422: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`
3423: @*/
3424: PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3425: {
3426: DMSubDomainHookLink link;
3428: for (link = global->subdomainhook; link; link = link->next) {
3429: if (link->restricthook) (*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx);
3430: }
3431: return 0;
3432: }
3434: /*@
3435: DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3437: Not Collective
3439: Input Parameter:
3440: . dm - the `DM` object
3442: Output Parameter:
3443: . level - number of coarsenings
3445: Level: developer
3447: .seealso: `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3448: @*/
3449: PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3450: {
3453: *level = dm->leveldown;
3454: return 0;
3455: }
3457: /*@
3458: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3460: Collective on dm
3462: Input Parameters:
3463: + dm - the `DM` object
3464: - level - number of coarsenings
3466: Level: developer
3468: Note:
3469: This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3471: .seealso: `DMSetCoarsenLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3472: @*/
3473: PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3474: {
3476: dm->leveldown = level;
3477: return 0;
3478: }
3480: /*@C
3481: DMRefineHierarchy - Refines a `DM` object, all levels at once
3483: Collective on dm
3485: Input Parameters:
3486: + dm - the `DM` object
3487: - nlevels - the number of levels of refinement
3489: Output Parameter:
3490: . dmf - the refined `DM` hierarchy
3492: Level: developer
3494: .seealso: `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3495: @*/
3496: PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3497: {
3500: if (nlevels == 0) return 0;
3502: if (dm->ops->refinehierarchy) {
3503: PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3504: } else if (dm->ops->refine) {
3505: PetscInt i;
3507: DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]);
3508: for (i = 1; i < nlevels; i++) DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]);
3509: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No RefineHierarchy for this DM yet");
3510: return 0;
3511: }
3513: /*@C
3514: DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3516: Collective on dm
3518: Input Parameters:
3519: + dm - the `DM` object
3520: - nlevels - the number of levels of coarsening
3522: Output Parameter:
3523: . dmc - the coarsened `DM` hierarchy
3525: Level: developer
3527: .seealso: `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3528: @*/
3529: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3530: {
3533: if (nlevels == 0) return 0;
3535: if (dm->ops->coarsenhierarchy) {
3536: PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3537: } else if (dm->ops->coarsen) {
3538: PetscInt i;
3540: DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]);
3541: for (i = 1; i < nlevels; i++) DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]);
3542: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No CoarsenHierarchy for this DM yet");
3543: return 0;
3544: }
3546: /*@C
3547: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3549: Logically Collective if the function is collective
3551: Input Parameters:
3552: + dm - the `DM` object
3553: - destroy - the destroy function
3555: Level: intermediate
3557: .seealso: `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3558: @*/
3559: PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3560: {
3562: dm->ctxdestroy = destroy;
3563: return 0;
3564: }
3566: /*@
3567: DMSetApplicationContext - Set a user context into a `DM` object
3569: Not Collective
3571: Input Parameters:
3572: + dm - the `DM` object
3573: - ctx - the user context
3575: Level: intermediate
3577: Note:
3578: A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3580: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3581: @*/
3582: PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3583: {
3585: dm->ctx = ctx;
3586: return 0;
3587: }
3589: /*@
3590: DMGetApplicationContext - Gets a user context from a `DM` object
3592: Not Collective
3594: Input Parameter:
3595: . dm - the `DM` object
3597: Output Parameter:
3598: . ctx - the user context
3600: Level: intermediate
3602: Note:
3603: A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3605: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3606: @*/
3607: PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3608: {
3610: *(void **)ctx = dm->ctx;
3611: return 0;
3612: }
3614: /*@C
3615: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3617: Logically Collective on dm
3619: Input Parameters:
3620: + dm - the DM object
3621: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3623: Level: intermediate
3625: .seealso: `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3626: `DMSetJacobian()`
3627: @*/
3628: PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3629: {
3631: dm->ops->computevariablebounds = f;
3632: return 0;
3633: }
3635: /*@
3636: DMHasVariableBounds - does the `DM` object have a variable bounds function?
3638: Not Collective
3640: Input Parameter:
3641: . dm - the `DM` object to destroy
3643: Output Parameter:
3644: . flg - `PETSC_TRUE` if the variable bounds function exists
3646: Level: developer
3648: .seealso: `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3649: @*/
3650: PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3651: {
3654: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3655: return 0;
3656: }
3658: /*@C
3659: DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3661: Logically Collective on dm
3663: Input Parameter:
3664: . dm - the `DM` object
3666: Output parameters:
3667: + xl - lower bound
3668: - xu - upper bound
3670: Level: advanced
3672: Notes:
3673: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3675: .seealso: `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3676: @*/
3677: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3678: {
3682: PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3683: return 0;
3684: }
3686: /*@
3687: DMHasColoring - does the `DM` object have a method of providing a coloring?
3689: Not Collective
3691: Input Parameter:
3692: . dm - the DM object
3694: Output Parameter:
3695: . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3697: Level: developer
3699: .seealso: `DMCreateColoring()`
3700: @*/
3701: PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3702: {
3705: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3706: return 0;
3707: }
3709: /*@
3710: DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3712: Not Collective
3714: Input Parameter:
3715: . dm - the `DM` object
3717: Output Parameter:
3718: . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3720: Level: developer
3722: .seealso: `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3723: @*/
3724: PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3725: {
3728: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3729: return 0;
3730: }
3732: /*@
3733: DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3735: Not Collective
3737: Input Parameter:
3738: . dm - the `DM` object
3740: Output Parameter:
3741: . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3743: Level: developer
3745: .seealso: `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3746: @*/
3747: PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3748: {
3751: if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3752: else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3753: return 0;
3754: }
3756: PetscFunctionList DMList = NULL;
3757: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3759: /*@C
3760: DMSetType - Builds a `DM`, for a particular `DM` implementation.
3762: Collective on dm
3764: Input Parameters:
3765: + dm - The `DM` object
3766: - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3768: Options Database Key:
3769: . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3771: Level: intermediate
3773: Note:
3774: Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPLEXCreateBoxMesh()`
3776: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3777: @*/
3778: PetscErrorCode DMSetType(DM dm, DMType method)
3779: {
3780: PetscErrorCode (*r)(DM);
3781: PetscBool match;
3784: PetscObjectTypeCompare((PetscObject)dm, method, &match);
3785: if (match) return 0;
3787: DMRegisterAll();
3788: PetscFunctionListFind(DMList, method, &r);
3791: PetscTryTypeMethod(dm, destroy);
3792: PetscMemzero(dm->ops, sizeof(*dm->ops));
3793: PetscObjectChangeTypeName((PetscObject)dm, method);
3794: (*r)(dm);
3795: return 0;
3796: }
3798: /*@C
3799: DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3801: Not Collective
3803: Input Parameter:
3804: . dm - The `DM`
3806: Output Parameter:
3807: . type - The `DMType` name
3809: Level: intermediate
3811: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3812: @*/
3813: PetscErrorCode DMGetType(DM dm, DMType *type)
3814: {
3817: DMRegisterAll();
3818: *type = ((PetscObject)dm)->type_name;
3819: return 0;
3820: }
3822: /*@C
3823: DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3825: Collective on dm
3827: Input Parameters:
3828: + dm - the `DM`
3829: - newtype - new `DM` type (use "same" for the same type)
3831: Output Parameter:
3832: . M - pointer to new `DM`
3834: Notes:
3835: Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3836: the MPI communicator of the generated `DM` is always the same as the communicator
3837: of the input `DM`.
3839: Level: intermediate
3841: .seealso: `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
3842: @*/
3843: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3844: {
3845: DM B;
3846: char convname[256];
3847: PetscBool sametype /*, issame */;
3852: PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype);
3853: /* PetscStrcmp(newtype, "same", &issame); */
3854: if (sametype) {
3855: *M = dm;
3856: PetscObjectReference((PetscObject)dm);
3857: return 0;
3858: } else {
3859: PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
3861: /*
3862: Order of precedence:
3863: 1) See if a specialized converter is known to the current DM.
3864: 2) See if a specialized converter is known to the desired DM class.
3865: 3) See if a good general converter is registered for the desired class
3866: 4) See if a good general converter is known for the current matrix.
3867: 5) Use a really basic converter.
3868: */
3870: /* 1) See if a specialized converter is known to the current DM and the desired class */
3871: PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3872: PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3873: PetscStrlcat(convname, "_", sizeof(convname));
3874: PetscStrlcat(convname, newtype, sizeof(convname));
3875: PetscStrlcat(convname, "_C", sizeof(convname));
3876: PetscObjectQueryFunction((PetscObject)dm, convname, &conv);
3877: if (conv) goto foundconv;
3879: /* 2) See if a specialized converter is known to the desired DM class. */
3880: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3881: DMSetType(B, newtype);
3882: PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3883: PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3884: PetscStrlcat(convname, "_", sizeof(convname));
3885: PetscStrlcat(convname, newtype, sizeof(convname));
3886: PetscStrlcat(convname, "_C", sizeof(convname));
3887: PetscObjectQueryFunction((PetscObject)B, convname, &conv);
3888: if (conv) {
3889: DMDestroy(&B);
3890: goto foundconv;
3891: }
3893: #if 0
3894: /* 3) See if a good general converter is registered for the desired class */
3895: conv = B->ops->convertfrom;
3896: DMDestroy(&B);
3897: if (conv) goto foundconv;
3899: /* 4) See if a good general converter is known for the current matrix */
3900: if (dm->ops->convert) {
3901: conv = dm->ops->convert;
3902: }
3903: if (conv) goto foundconv;
3904: #endif
3906: /* 5) Use a really basic converter. */
3907: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
3909: foundconv:
3910: PetscLogEventBegin(DM_Convert, dm, 0, 0, 0);
3911: (*conv)(dm, newtype, M);
3912: /* Things that are independent of DM type: We should consult DMClone() here */
3913: {
3914: const PetscReal *maxCell, *Lstart, *L;
3916: DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
3917: DMSetPeriodicity(*M, maxCell, Lstart, L);
3918: (*M)->prealloc_only = dm->prealloc_only;
3919: PetscFree((*M)->vectype);
3920: PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype);
3921: PetscFree((*M)->mattype);
3922: PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype);
3923: }
3924: PetscLogEventEnd(DM_Convert, dm, 0, 0, 0);
3925: }
3926: PetscObjectStateIncrease((PetscObject)*M);
3927: return 0;
3928: }
3930: /*--------------------------------------------------------------------------------------------------------------------*/
3932: /*@C
3933: DMRegister - Adds a new `DM` type implementation
3935: Not Collective
3937: Input Parameters:
3938: + name - The name of a new user-defined creation routine
3939: - create_func - The creation routine itself
3941: Notes:
3942: DMRegister() may be called multiple times to add several user-defined `DM`s
3944: Sample usage:
3945: .vb
3946: DMRegister("my_da", MyDMCreate);
3947: .ve
3949: Then, your DM type can be chosen with the procedural interface via
3950: .vb
3951: DMCreate(MPI_Comm, DM *);
3952: DMSetType(DM,"my_da");
3953: .ve
3954: or at runtime via the option
3955: .vb
3956: -da_type my_da
3957: .ve
3959: Level: advanced
3961: .seealso: `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
3962: @*/
3963: PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
3964: {
3965: DMInitializePackage();
3966: PetscFunctionListAdd(&DMList, sname, function);
3967: return 0;
3968: }
3970: /*@C
3971: DMLoad - Loads a DM that has been stored in binary with `DMView()`.
3973: Collective on viewer
3975: Input Parameters:
3976: + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
3977: some related function before a call to `DMLoad()`.
3978: - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
3979: `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
3981: Level: intermediate
3983: Notes:
3984: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3986: Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
3987: meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
3988: before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
3990: Notes for advanced users:
3991: Most users should not need to know the details of the binary storage
3992: format, since `DMLoad()` and `DMView()` completely hide these details.
3993: But for anyone who's interested, the standard binary matrix storage
3994: format is
3995: .vb
3996: has not yet been determined
3997: .ve
3999: .seealso: `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4000: @*/
4001: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4002: {
4003: PetscBool isbinary, ishdf5;
4007: PetscViewerCheckReadable(viewer);
4008: PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary);
4009: PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
4010: PetscLogEventBegin(DM_Load, viewer, 0, 0, 0);
4011: if (isbinary) {
4012: PetscInt classid;
4013: char type[256];
4015: PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT);
4017: PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR);
4018: DMSetType(newdm, type);
4019: PetscTryTypeMethod(newdm, load, viewer);
4020: } else if (ishdf5) {
4021: PetscTryTypeMethod(newdm, load, viewer);
4022: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4023: PetscLogEventEnd(DM_Load, viewer, 0, 0, 0);
4024: return 0;
4025: }
4027: /******************************** FEM Support **********************************/
4029: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4030: {
4031: PetscInt f;
4033: PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name);
4034: for (f = 0; f < len; ++f) PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
4035: return 0;
4036: }
4038: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4039: {
4040: PetscInt f, g;
4042: PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name);
4043: for (f = 0; f < rows; ++f) {
4044: PetscPrintf(PETSC_COMM_SELF, " |");
4045: for (g = 0; g < cols; ++g) PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g]));
4046: PetscPrintf(PETSC_COMM_SELF, " |\n");
4047: }
4048: return 0;
4049: }
4051: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4052: {
4053: PetscInt localSize, bs;
4054: PetscMPIInt size;
4055: Vec x, xglob;
4056: const PetscScalar *xarray;
4058: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
4059: VecDuplicate(X, &x);
4060: VecCopy(X, x);
4061: VecChop(x, tol);
4062: PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name);
4063: if (size > 1) {
4064: VecGetLocalSize(x, &localSize);
4065: VecGetArrayRead(x, &xarray);
4066: VecGetBlockSize(x, &bs);
4067: VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob);
4068: } else {
4069: xglob = x;
4070: }
4071: VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm)));
4072: if (size > 1) {
4073: VecDestroy(&xglob);
4074: VecRestoreArrayRead(x, &xarray);
4075: }
4076: VecDestroy(&x);
4077: return 0;
4078: }
4080: /*@
4081: DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`. This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4083: Input Parameter:
4084: . dm - The `DM`
4086: Output Parameter:
4087: . section - The `PetscSection`
4089: Options Database Keys:
4090: . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4092: Level: advanced
4094: Notes:
4095: Use `DMGetLocalSection()` in new code.
4097: This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4099: .seealso: `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4100: @*/
4101: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4102: {
4103: DMGetLocalSection(dm, section);
4104: return 0;
4105: }
4107: /*@
4108: DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4110: Input Parameter:
4111: . dm - The `DM`
4113: Output Parameter:
4114: . section - The `PetscSection`
4116: Options Database Keys:
4117: . -dm_petscsection_view - View the section created by the `DM`
4119: Level: intermediate
4121: Note:
4122: This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4124: .seealso: `DMSetLocalSection()`, `DMGetGlobalSection()`
4125: @*/
4126: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4127: {
4130: if (!dm->localSection && dm->ops->createlocalsection) {
4131: PetscInt d;
4133: if (dm->setfromoptionscalled) {
4134: PetscObject obj = (PetscObject)dm;
4135: PetscViewer viewer;
4136: PetscViewerFormat format;
4137: PetscBool flg;
4139: PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4140: if (flg) PetscViewerPushFormat(viewer, format);
4141: for (d = 0; d < dm->Nds; ++d) {
4142: PetscDSSetFromOptions(dm->probs[d].ds);
4143: if (flg) PetscDSView(dm->probs[d].ds, viewer);
4144: }
4145: if (flg) {
4146: PetscViewerFlush(viewer);
4147: PetscViewerPopFormat(viewer);
4148: PetscViewerDestroy(&viewer);
4149: }
4150: }
4151: PetscUseTypeMethod(dm, createlocalsection);
4152: if (dm->localSection) PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view");
4153: }
4154: *section = dm->localSection;
4155: return 0;
4156: }
4158: /*@
4159: DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`. This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4161: Input Parameters:
4162: + dm - The `DM`
4163: - section - The `PetscSection`
4165: Level: advanced
4167: Notes:
4168: Use `DMSetLocalSection()` in new code.
4170: Any existing `PetscSection` will be destroyed
4172: .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4173: @*/
4174: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4175: {
4176: DMSetLocalSection(dm, section);
4177: return 0;
4178: }
4180: /*@
4181: DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4183: Input Parameters:
4184: + dm - The `DM`
4185: - section - The `PetscSection`
4187: Level: intermediate
4189: Note:
4190: Any existing Section will be destroyed
4192: .seealso: `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4193: @*/
4194: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4195: {
4196: PetscInt numFields = 0;
4197: PetscInt f;
4201: PetscObjectReference((PetscObject)section);
4202: PetscSectionDestroy(&dm->localSection);
4203: dm->localSection = section;
4204: if (section) PetscSectionGetNumFields(dm->localSection, &numFields);
4205: if (numFields) {
4206: DMSetNumFields(dm, numFields);
4207: for (f = 0; f < numFields; ++f) {
4208: PetscObject disc;
4209: const char *name;
4211: PetscSectionGetFieldName(dm->localSection, f, &name);
4212: DMGetField(dm, f, NULL, &disc);
4213: PetscObjectSetName(disc, name);
4214: }
4215: }
4216: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4217: PetscSectionDestroy(&dm->globalSection);
4218: return 0;
4219: }
4221: /*@
4222: DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4224: not collective
4226: Input Parameter:
4227: . dm - The `DM`
4229: Output Parameters:
4230: + 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.
4231: . 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.
4232: - bias - Vector containing bias to be added to constrained dofs
4234: Level: advanced
4236: Note:
4237: This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4239: .seealso: `DMSetDefaultConstraints()`
4240: @*/
4241: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4242: {
4244: if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4245: if (section) *section = dm->defaultConstraint.section;
4246: if (mat) *mat = dm->defaultConstraint.mat;
4247: if (bias) *bias = dm->defaultConstraint.bias;
4248: return 0;
4249: }
4251: /*@
4252: DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4254: 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 + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`.
4256: 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. Any bias, if specified, is ignored when accumulating.
4258: collective on dm
4260: Input Parameters:
4261: + dm - The `DM`
4262: . 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).
4263: . 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).
4264: - bias - A bias vector to be added to constrained values in the local vector. NULL indicates no bias. Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4266: Level: advanced
4268: Note:
4269: This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4271: .seealso: `DMGetDefaultConstraints()`
4272: @*/
4273: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4274: {
4275: PetscMPIInt result;
4278: if (section) {
4280: MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result);
4282: }
4283: if (mat) {
4285: MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result);
4287: }
4288: if (bias) {
4290: MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result);
4292: }
4293: PetscObjectReference((PetscObject)section);
4294: PetscSectionDestroy(&dm->defaultConstraint.section);
4295: dm->defaultConstraint.section = section;
4296: PetscObjectReference((PetscObject)mat);
4297: MatDestroy(&dm->defaultConstraint.mat);
4298: dm->defaultConstraint.mat = mat;
4299: PetscObjectReference((PetscObject)bias);
4300: VecDestroy(&dm->defaultConstraint.bias);
4301: dm->defaultConstraint.bias = bias;
4302: return 0;
4303: }
4305: #if defined(PETSC_USE_DEBUG)
4306: /*
4307: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4309: Input Parameters:
4310: + dm - The `DM`
4311: . localSection - `PetscSection` describing the local data layout
4312: - globalSection - `PetscSection` describing the global data layout
4314: Level: intermediate
4316: .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`
4317: */
4318: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4319: {
4320: MPI_Comm comm;
4321: PetscLayout layout;
4322: const PetscInt *ranges;
4323: PetscInt pStart, pEnd, p, nroots;
4324: PetscMPIInt size, rank;
4325: PetscBool valid = PETSC_TRUE, gvalid;
4327: PetscObjectGetComm((PetscObject)dm, &comm);
4329: MPI_Comm_size(comm, &size);
4330: MPI_Comm_rank(comm, &rank);
4331: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4332: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4333: PetscLayoutCreate(comm, &layout);
4334: PetscLayoutSetBlockSize(layout, 1);
4335: PetscLayoutSetLocalSize(layout, nroots);
4336: PetscLayoutSetUp(layout);
4337: PetscLayoutGetRanges(layout, &ranges);
4338: for (p = pStart; p < pEnd; ++p) {
4339: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4341: PetscSectionGetDof(localSection, p, &dof);
4342: PetscSectionGetOffset(localSection, p, &off);
4343: PetscSectionGetConstraintDof(localSection, p, &cdof);
4344: PetscSectionGetDof(globalSection, p, &gdof);
4345: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4346: PetscSectionGetOffset(globalSection, p, &goff);
4347: if (!gdof) continue; /* Censored point */
4348: if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4349: PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof);
4350: valid = PETSC_FALSE;
4351: }
4352: if (gcdof && (gcdof != cdof)) {
4353: PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof);
4354: valid = PETSC_FALSE;
4355: }
4356: if (gdof < 0) {
4357: gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4358: for (d = 0; d < gsize; ++d) {
4359: PetscInt offset = -(goff + 1) + d, r;
4361: PetscFindInt(offset, size + 1, ranges, &r);
4362: if (r < 0) r = -(r + 2);
4363: if ((r < 0) || (r >= size)) {
4364: PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff);
4365: valid = PETSC_FALSE;
4366: break;
4367: }
4368: }
4369: }
4370: }
4371: PetscLayoutDestroy(&layout);
4372: PetscSynchronizedFlush(comm, NULL);
4373: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4374: if (!gvalid) {
4375: DMView(dm, NULL);
4376: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4377: }
4378: return 0;
4379: }
4380: #endif
4382: /*@
4383: DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4385: Collective on dm
4387: Input Parameter:
4388: . dm - The `DM`
4390: Output Parameter:
4391: . section - The `PetscSection`
4393: Level: intermediate
4395: Note:
4396: This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4398: .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`
4399: @*/
4400: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4401: {
4404: if (!dm->globalSection) {
4405: PetscSection s;
4407: DMGetLocalSection(dm, &s);
4410: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4411: PetscLayoutDestroy(&dm->map);
4412: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4413: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4414: }
4415: *section = dm->globalSection;
4416: return 0;
4417: }
4419: /*@
4420: DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4422: Input Parameters:
4423: + dm - The `DM`
4424: - section - The PetscSection, or NULL
4426: Level: intermediate
4428: Note:
4429: Any existing `PetscSection` will be destroyed
4431: .seealso: `DMGetGlobalSection()`, `DMSetLocalSection()`
4432: @*/
4433: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4434: {
4437: PetscObjectReference((PetscObject)section);
4438: PetscSectionDestroy(&dm->globalSection);
4439: dm->globalSection = section;
4440: #if defined(PETSC_USE_DEBUG)
4441: if (section) DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);
4442: #endif
4443: return 0;
4444: }
4446: /*@
4447: DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4448: it is created from the default `PetscSection` layouts in the `DM`.
4450: Input Parameter:
4451: . dm - The `DM`
4453: Output Parameter:
4454: . sf - The `PetscSF`
4456: Level: intermediate
4458: Note:
4459: This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4461: .seealso: `DMSetSectionSF()`, `DMCreateSectionSF()`
4462: @*/
4463: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4464: {
4465: PetscInt nroots;
4469: if (!dm->sectionSF) PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF);
4470: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4471: if (nroots < 0) {
4472: PetscSection section, gSection;
4474: DMGetLocalSection(dm, §ion);
4475: if (section) {
4476: DMGetGlobalSection(dm, &gSection);
4477: DMCreateSectionSF(dm, section, gSection);
4478: } else {
4479: *sf = NULL;
4480: return 0;
4481: }
4482: }
4483: *sf = dm->sectionSF;
4484: return 0;
4485: }
4487: /*@
4488: DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4490: Input Parameters:
4491: + dm - The `DM`
4492: - sf - The `PetscSF`
4494: Level: intermediate
4496: Note:
4497: Any previous `PetscSF` is destroyed
4499: .seealso: `DMGetSectionSF()`, `DMCreateSectionSF()`
4500: @*/
4501: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4502: {
4505: PetscObjectReference((PetscObject)sf);
4506: PetscSFDestroy(&dm->sectionSF);
4507: dm->sectionSF = sf;
4508: return 0;
4509: }
4511: /*@C
4512: DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4513: describing the data layout.
4515: Input Parameters:
4516: + dm - The `DM`
4517: . localSection - `PetscSection` describing the local data layout
4518: - globalSection - `PetscSection` describing the global data layout
4520: Level: developer
4522: Note:
4523: One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4525: Developer Note:
4526: Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4527: directly into the `DM`, perhaps this function should not take the local and global sections as
4528: input and should just obtain them from the `DM`?
4530: .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4531: @*/
4532: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4533: {
4535: PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4536: return 0;
4537: }
4539: /*@
4540: DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4542: Not collective but the resulting `PetscSF` is collective
4544: Input Parameter:
4545: . dm - The `DM`
4547: Output Parameter:
4548: . sf - The `PetscSF`
4550: Level: intermediate
4552: Note:
4553: This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4555: .seealso: `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4556: @*/
4557: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4558: {
4561: *sf = dm->sf;
4562: return 0;
4563: }
4565: /*@
4566: DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4568: Collective on dm
4570: Input Parameters:
4571: + dm - The `DM`
4572: - sf - The `PetscSF`
4574: Level: intermediate
4576: .seealso: `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4577: @*/
4578: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4579: {
4582: PetscObjectReference((PetscObject)sf);
4583: PetscSFDestroy(&dm->sf);
4584: dm->sf = sf;
4585: return 0;
4586: }
4588: /*@
4589: DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4591: Input Parameter:
4592: . dm - The `DM`
4594: Output Parameter:
4595: . sf - The `PetscSF`
4597: Level: intermediate
4599: Note:
4600: This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4602: .seealso: `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4603: @*/
4604: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4605: {
4608: *sf = dm->sfNatural;
4609: return 0;
4610: }
4612: /*@
4613: DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4615: Input Parameters:
4616: + dm - The DM
4617: - sf - The PetscSF
4619: Level: intermediate
4621: .seealso: `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4622: @*/
4623: PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4624: {
4627: PetscObjectReference((PetscObject)sf);
4628: PetscSFDestroy(&dm->sfNatural);
4629: dm->sfNatural = sf;
4630: return 0;
4631: }
4633: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4634: {
4635: PetscClassId id;
4637: PetscObjectGetClassId(disc, &id);
4638: if (id == PETSCFE_CLASSID) {
4639: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4640: } else if (id == PETSCFV_CLASSID) {
4641: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4642: } else {
4643: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4644: }
4645: return 0;
4646: }
4648: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4649: {
4650: RegionField *tmpr;
4651: PetscInt Nf = dm->Nf, f;
4653: if (Nf >= NfNew) return 0;
4654: PetscMalloc1(NfNew, &tmpr);
4655: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4656: for (f = Nf; f < NfNew; ++f) {
4657: tmpr[f].disc = NULL;
4658: tmpr[f].label = NULL;
4659: tmpr[f].avoidTensor = PETSC_FALSE;
4660: }
4661: PetscFree(dm->fields);
4662: dm->Nf = NfNew;
4663: dm->fields = tmpr;
4664: return 0;
4665: }
4667: /*@
4668: DMClearFields - Remove all fields from the DM
4670: Logically collective on dm
4672: Input Parameter:
4673: . dm - The DM
4675: Level: intermediate
4677: .seealso: `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4678: @*/
4679: PetscErrorCode DMClearFields(DM dm)
4680: {
4681: PetscInt f;
4684: for (f = 0; f < dm->Nf; ++f) {
4685: PetscObjectDestroy(&dm->fields[f].disc);
4686: DMLabelDestroy(&dm->fields[f].label);
4687: }
4688: PetscFree(dm->fields);
4689: dm->fields = NULL;
4690: dm->Nf = 0;
4691: return 0;
4692: }
4694: /*@
4695: DMGetNumFields - Get the number of fields in the DM
4697: Not collective
4699: Input Parameter:
4700: . dm - The DM
4702: Output Parameter:
4703: . Nf - The number of fields
4705: Level: intermediate
4707: .seealso: `DMSetNumFields()`, `DMSetField()`
4708: @*/
4709: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4710: {
4713: *numFields = dm->Nf;
4714: return 0;
4715: }
4717: /*@
4718: DMSetNumFields - Set the number of fields in the DM
4720: Logically collective on dm
4722: Input Parameters:
4723: + dm - The DM
4724: - Nf - The number of fields
4726: Level: intermediate
4728: .seealso: `DMGetNumFields()`, `DMSetField()`
4729: @*/
4730: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4731: {
4732: PetscInt Nf, f;
4735: DMGetNumFields(dm, &Nf);
4736: for (f = Nf; f < numFields; ++f) {
4737: PetscContainer obj;
4739: PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj);
4740: DMAddField(dm, NULL, (PetscObject)obj);
4741: PetscContainerDestroy(&obj);
4742: }
4743: return 0;
4744: }
4746: /*@
4747: DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
4749: Not collective
4751: Input Parameters:
4752: + dm - The `DM`
4753: - f - The field number
4755: Output Parameters:
4756: + label - The label indicating the support of the field, or NULL for the entire mesh (pass in NULL if not needed)
4757: - disc - The discretization object (pass in NULL if not needed)
4759: Level: intermediate
4761: .seealso: `DMAddField()`, `DMSetField()`
4762: @*/
4763: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4764: {
4768: if (label) *label = dm->fields[f].label;
4769: if (disc) *disc = dm->fields[f].disc;
4770: return 0;
4771: }
4773: /* Does not clear the DS */
4774: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4775: {
4776: DMFieldEnlarge_Static(dm, f + 1);
4777: DMLabelDestroy(&dm->fields[f].label);
4778: PetscObjectDestroy(&dm->fields[f].disc);
4779: dm->fields[f].label = label;
4780: dm->fields[f].disc = disc;
4781: PetscObjectReference((PetscObject)label);
4782: PetscObjectReference((PetscObject)disc);
4783: return 0;
4784: }
4786: /*@
4787: DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
4788: the field numbering.
4790: Logically collective on dm
4792: Input Parameters:
4793: + dm - The `DM`
4794: . f - The field number
4795: . label - The label indicating the support of the field, or NULL for the entire mesh
4796: - disc - The discretization object
4798: Level: intermediate
4800: .seealso: `DMAddField()`, `DMGetField()`
4801: @*/
4802: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4803: {
4808: DMSetField_Internal(dm, f, label, disc);
4809: DMSetDefaultAdjacency_Private(dm, f, disc);
4810: DMClearDS(dm);
4811: return 0;
4812: }
4814: /*@
4815: DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
4816: and a discretization object that defines the function space associated with those points.
4818: Logically collective on dm
4820: Input Parameters:
4821: + dm - The `DM`
4822: . label - The label indicating the support of the field, or NULL for the entire mesh
4823: - disc - The discretization object
4825: Level: intermediate
4827: Notes:
4828: The label already exists or will be added to the `DM` with `DMSetLabel()`.
4830: For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
4831: within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
4832: geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
4834: .seealso: `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
4835: @*/
4836: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
4837: {
4838: PetscInt Nf = dm->Nf;
4843: DMFieldEnlarge_Static(dm, Nf + 1);
4844: dm->fields[Nf].label = label;
4845: dm->fields[Nf].disc = disc;
4846: PetscObjectReference((PetscObject)label);
4847: PetscObjectReference((PetscObject)disc);
4848: DMSetDefaultAdjacency_Private(dm, Nf, disc);
4849: DMClearDS(dm);
4850: return 0;
4851: }
4853: /*@
4854: DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4856: Logically collective on dm
4858: Input Parameters:
4859: + dm - The `DM`
4860: . f - The field index
4861: - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
4863: Level: intermediate
4865: .seealso: `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4866: @*/
4867: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4868: {
4870: dm->fields[f].avoidTensor = avoidTensor;
4871: return 0;
4872: }
4874: /*@
4875: DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4877: Not collective
4879: Input Parameters:
4880: + dm - The `DM`
4881: - f - The field index
4883: Output Parameter:
4884: . avoidTensor - The flag to avoid defining the field on tensor cells
4886: Level: intermediate
4888: .seealso: `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4889: @*/
4890: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4891: {
4893: *avoidTensor = dm->fields[f].avoidTensor;
4894: return 0;
4895: }
4897: /*@
4898: DMCopyFields - Copy the discretizations for the `DM` into another `DM`
4900: Collective on dm
4902: Input Parameter:
4903: . dm - The `DM`
4905: Output Parameter:
4906: . newdm - The `DM`
4908: Level: advanced
4910: .seealso: `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
4911: @*/
4912: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4913: {
4914: PetscInt Nf, f;
4916: if (dm == newdm) return 0;
4917: DMGetNumFields(dm, &Nf);
4918: DMClearFields(newdm);
4919: for (f = 0; f < Nf; ++f) {
4920: DMLabel label;
4921: PetscObject field;
4922: PetscBool useCone, useClosure;
4924: DMGetField(dm, f, &label, &field);
4925: DMSetField(newdm, f, label, field);
4926: DMGetAdjacency(dm, f, &useCone, &useClosure);
4927: DMSetAdjacency(newdm, f, useCone, useClosure);
4928: }
4929: return 0;
4930: }
4932: /*@
4933: DMGetAdjacency - Returns the flags for determining variable influence
4935: Not collective
4937: Input Parameters:
4938: + dm - The DM object
4939: - f - The field number, or PETSC_DEFAULT for the default adjacency
4941: Output Parameters:
4942: + useCone - Flag for variable influence starting with the cone operation
4943: - useClosure - Flag for variable influence using transitive closure
4945: Notes:
4946: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4947: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4948: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4949: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4951: Level: developer
4953: .seealso: `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
4954: @*/
4955: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4956: {
4960: if (f < 0) {
4961: if (useCone) *useCone = dm->adjacency[0];
4962: if (useClosure) *useClosure = dm->adjacency[1];
4963: } else {
4964: PetscInt Nf;
4966: DMGetNumFields(dm, &Nf);
4968: if (useCone) *useCone = dm->fields[f].adjacency[0];
4969: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4970: }
4971: return 0;
4972: }
4974: /*@
4975: DMSetAdjacency - Set the flags for determining variable influence
4977: Not collective
4979: Input Parameters:
4980: + dm - The DM object
4981: . f - The field number
4982: . useCone - Flag for variable influence starting with the cone operation
4983: - useClosure - Flag for variable influence using transitive closure
4985: Notes:
4986: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4987: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4988: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4989: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4991: Level: developer
4993: .seealso: `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
4994: @*/
4995: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4996: {
4998: if (f < 0) {
4999: dm->adjacency[0] = useCone;
5000: dm->adjacency[1] = useClosure;
5001: } else {
5002: PetscInt Nf;
5004: DMGetNumFields(dm, &Nf);
5006: dm->fields[f].adjacency[0] = useCone;
5007: dm->fields[f].adjacency[1] = useClosure;
5008: }
5009: return 0;
5010: }
5012: /*@
5013: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5015: Not collective
5017: Input Parameter:
5018: . dm - The DM object
5020: Output Parameters:
5021: + useCone - Flag for variable influence starting with the cone operation
5022: - useClosure - Flag for variable influence using transitive closure
5024: Notes:
5025: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5026: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5027: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5029: Level: developer
5031: .seealso: `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5032: @*/
5033: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5034: {
5035: PetscInt Nf;
5040: DMGetNumFields(dm, &Nf);
5041: if (!Nf) {
5042: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5043: } else {
5044: DMGetAdjacency(dm, 0, useCone, useClosure);
5045: }
5046: return 0;
5047: }
5049: /*@
5050: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5052: Not collective
5054: Input Parameters:
5055: + dm - The DM object
5056: . useCone - Flag for variable influence starting with the cone operation
5057: - useClosure - Flag for variable influence using transitive closure
5059: Notes:
5060: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5061: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5062: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5064: Level: developer
5066: .seealso: `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5067: @*/
5068: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5069: {
5070: PetscInt Nf;
5073: DMGetNumFields(dm, &Nf);
5074: if (!Nf) {
5075: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5076: } else {
5077: DMSetAdjacency(dm, 0, useCone, useClosure);
5078: }
5079: return 0;
5080: }
5082: PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5083: {
5084: DM plex;
5085: DMLabel *labels, *glabels;
5086: const char **names;
5087: char *sendNames, *recvNames;
5088: PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5089: size_t len;
5090: MPI_Comm comm;
5091: PetscMPIInt rank, size, p, *counts, *displs;
5093: PetscObjectGetComm((PetscObject)dm, &comm);
5094: MPI_Comm_size(comm, &size);
5095: MPI_Comm_rank(comm, &rank);
5096: DMGetNumDS(dm, &Nds);
5097: for (s = 0; s < Nds; ++s) {
5098: PetscDS dsBC;
5099: PetscInt numBd;
5101: DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5102: PetscDSGetNumBoundary(dsBC, &numBd);
5103: maxLabels += numBd;
5104: }
5105: PetscCalloc1(maxLabels, &labels);
5106: /* Get list of labels to be completed */
5107: for (s = 0; s < Nds; ++s) {
5108: PetscDS dsBC;
5109: PetscInt numBd, bd;
5111: DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5112: PetscDSGetNumBoundary(dsBC, &numBd);
5113: for (bd = 0; bd < numBd; ++bd) {
5114: DMLabel label;
5115: PetscInt field;
5116: PetscObject obj;
5117: PetscClassId id;
5119: PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5120: DMGetField(dm, field, NULL, &obj);
5121: PetscObjectGetClassId(obj, &id);
5122: if (!(id == PETSCFE_CLASSID) || !label) continue;
5123: for (l = 0; l < Nl; ++l)
5124: if (labels[l] == label) break;
5125: if (l == Nl) labels[Nl++] = label;
5126: }
5127: }
5128: /* Get label names */
5129: PetscMalloc1(Nl, &names);
5130: for (l = 0; l < Nl; ++l) PetscObjectGetName((PetscObject)labels[l], &names[l]);
5131: for (l = 0; l < Nl; ++l) {
5132: PetscStrlen(names[l], &len);
5133: maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5134: }
5135: PetscFree(labels);
5136: MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm);
5137: PetscCalloc1(Nl * gmaxLen, &sendNames);
5138: for (l = 0; l < Nl; ++l) PetscStrcpy(&sendNames[gmaxLen * l], names[l]);
5139: PetscFree(names);
5140: /* Put all names on all processes */
5141: PetscCalloc2(size, &counts, size + 1, &displs);
5142: MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm);
5143: for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5144: gNl = displs[size];
5145: for (p = 0; p < size; ++p) {
5146: counts[p] *= gmaxLen;
5147: displs[p] *= gmaxLen;
5148: }
5149: PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels);
5150: MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm);
5151: PetscFree2(counts, displs);
5152: PetscFree(sendNames);
5153: for (l = 0, gl = 0; l < gNl; ++l) {
5154: DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]);
5156: for (m = 0; m < gl; ++m)
5157: if (glabels[m] == glabels[gl]) continue;
5158: DMConvert(dm, DMPLEX, &plex);
5159: DMPlexLabelComplete(plex, glabels[gl]);
5160: DMDestroy(&plex);
5161: ++gl;
5162: }
5163: PetscFree2(recvNames, glabels);
5164: return 0;
5165: }
5167: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5168: {
5169: DMSpace *tmpd;
5170: PetscInt Nds = dm->Nds, s;
5172: if (Nds >= NdsNew) return 0;
5173: PetscMalloc1(NdsNew, &tmpd);
5174: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5175: for (s = Nds; s < NdsNew; ++s) {
5176: tmpd[s].ds = NULL;
5177: tmpd[s].label = NULL;
5178: tmpd[s].fields = NULL;
5179: }
5180: PetscFree(dm->probs);
5181: dm->Nds = NdsNew;
5182: dm->probs = tmpd;
5183: return 0;
5184: }
5186: /*@
5187: DMGetNumDS - Get the number of discrete systems in the DM
5189: Not collective
5191: Input Parameter:
5192: . dm - The DM
5194: Output Parameter:
5195: . Nds - The number of PetscDS objects
5197: Level: intermediate
5199: .seealso: `DMGetDS()`, `DMGetCellDS()`
5200: @*/
5201: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5202: {
5205: *Nds = dm->Nds;
5206: return 0;
5207: }
5209: /*@
5210: DMClearDS - Remove all discrete systems from the DM
5212: Logically collective on dm
5214: Input Parameter:
5215: . dm - The DM
5217: Level: intermediate
5219: .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5220: @*/
5221: PetscErrorCode DMClearDS(DM dm)
5222: {
5223: PetscInt s;
5226: for (s = 0; s < dm->Nds; ++s) {
5227: PetscDSDestroy(&dm->probs[s].ds);
5228: DMLabelDestroy(&dm->probs[s].label);
5229: ISDestroy(&dm->probs[s].fields);
5230: }
5231: PetscFree(dm->probs);
5232: dm->probs = NULL;
5233: dm->Nds = 0;
5234: return 0;
5235: }
5237: /*@
5238: DMGetDS - Get the default PetscDS
5240: Not collective
5242: Input Parameter:
5243: . dm - The DM
5245: Output Parameter:
5246: . prob - The default PetscDS
5248: Level: intermediate
5250: .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5251: @*/
5252: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5253: {
5257: if (dm->Nds <= 0) {
5258: PetscDS ds;
5260: PetscDSCreate(PETSC_COMM_SELF, &ds);
5261: DMSetRegionDS(dm, NULL, NULL, ds);
5262: PetscDSDestroy(&ds);
5263: }
5264: *prob = dm->probs[0].ds;
5265: return 0;
5266: }
5268: /*@
5269: DMGetCellDS - Get the PetscDS defined on a given cell
5271: Not collective
5273: Input Parameters:
5274: + dm - The DM
5275: - point - Cell for the DS
5277: Output Parameter:
5278: . prob - The PetscDS defined on the given cell
5280: Level: developer
5282: .seealso: `DMGetDS()`, `DMSetRegionDS()`
5283: @*/
5284: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5285: {
5286: PetscDS probDef = NULL;
5287: PetscInt s;
5293: *prob = NULL;
5294: for (s = 0; s < dm->Nds; ++s) {
5295: PetscInt val;
5297: if (!dm->probs[s].label) {
5298: probDef = dm->probs[s].ds;
5299: } else {
5300: DMLabelGetValue(dm->probs[s].label, point, &val);
5301: if (val >= 0) {
5302: *prob = dm->probs[s].ds;
5303: break;
5304: }
5305: }
5306: }
5307: if (!*prob) *prob = probDef;
5308: return 0;
5309: }
5311: /*@
5312: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5314: Not collective
5316: Input Parameters:
5317: + dm - The DM
5318: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5320: Output Parameters:
5321: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5322: - prob - The PetscDS defined on the given region, or NULL
5324: Note:
5325: If a non-NULL label is given, but there is no PetscDS on that specific label,
5326: the PetscDS for the full domain (if present) is returned. Returns with
5327: fields=NULL and prob=NULL if there is no PetscDS for the full domain.
5329: Level: advanced
5331: .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5332: @*/
5333: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5334: {
5335: PetscInt Nds = dm->Nds, s;
5339: if (fields) {
5341: *fields = NULL;
5342: }
5343: if (ds) {
5345: *ds = NULL;
5346: }
5347: for (s = 0; s < Nds; ++s) {
5348: if (dm->probs[s].label == label || !dm->probs[s].label) {
5349: if (fields) *fields = dm->probs[s].fields;
5350: if (ds) *ds = dm->probs[s].ds;
5351: if (dm->probs[s].label) return 0;
5352: }
5353: }
5354: return 0;
5355: }
5357: /*@
5358: DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5360: Collective on dm
5362: Input Parameters:
5363: + dm - The `DM`
5364: . label - The `DMLabel` defining the mesh region, or NULL for the entire mesh
5365: . fields - The IS containing the `DM` field numbers for the fields in this `PetscDS`, or NULL for all fields
5366: - prob - The `PetscDS` defined on the given region
5368: Note:
5369: If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5370: the fields argument is ignored.
5372: Level: advanced
5374: .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5375: @*/
5376: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5377: {
5378: PetscInt Nds = dm->Nds, s;
5383: for (s = 0; s < Nds; ++s) {
5384: if (dm->probs[s].label == label) {
5385: PetscDSDestroy(&dm->probs[s].ds);
5386: dm->probs[s].ds = ds;
5387: return 0;
5388: }
5389: }
5390: DMDSEnlarge_Static(dm, Nds + 1);
5391: PetscObjectReference((PetscObject)label);
5392: PetscObjectReference((PetscObject)fields);
5393: PetscObjectReference((PetscObject)ds);
5394: if (!label) {
5395: /* Put the NULL label at the front, so it is returned as the default */
5396: for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5397: Nds = 0;
5398: }
5399: dm->probs[Nds].label = label;
5400: dm->probs[Nds].fields = fields;
5401: dm->probs[Nds].ds = ds;
5402: return 0;
5403: }
5405: /*@
5406: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5408: Not collective
5410: Input Parameters:
5411: + dm - The DM
5412: - num - The region number, in [0, Nds)
5414: Output Parameters:
5415: + label - The region label, or NULL
5416: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5417: - ds - The PetscDS defined on the given region, or NULL
5419: Level: advanced
5421: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5422: @*/
5423: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5424: {
5425: PetscInt Nds;
5428: DMGetNumDS(dm, &Nds);
5430: if (label) {
5432: *label = dm->probs[num].label;
5433: }
5434: if (fields) {
5436: *fields = dm->probs[num].fields;
5437: }
5438: if (ds) {
5440: *ds = dm->probs[num].ds;
5441: }
5442: return 0;
5443: }
5445: /*@
5446: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5448: Not collective
5450: Input Parameters:
5451: + dm - The DM
5452: . num - The region number, in [0, Nds)
5453: . label - The region label, or NULL
5454: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5455: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5457: Level: advanced
5459: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5460: @*/
5461: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5462: {
5463: PetscInt Nds;
5467: DMGetNumDS(dm, &Nds);
5469: PetscObjectReference((PetscObject)label);
5470: DMLabelDestroy(&dm->probs[num].label);
5471: dm->probs[num].label = label;
5472: if (fields) {
5474: PetscObjectReference((PetscObject)fields);
5475: ISDestroy(&dm->probs[num].fields);
5476: dm->probs[num].fields = fields;
5477: }
5478: if (ds) {
5480: PetscObjectReference((PetscObject)ds);
5481: PetscDSDestroy(&dm->probs[num].ds);
5482: dm->probs[num].ds = ds;
5483: }
5484: return 0;
5485: }
5487: /*@
5488: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5490: Not collective
5492: Input Parameters:
5493: + dm - The DM
5494: - ds - The PetscDS defined on the given region
5496: Output Parameter:
5497: . num - The region number, in [0, Nds), or -1 if not found
5499: Level: advanced
5501: .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5502: @*/
5503: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5504: {
5505: PetscInt Nds, n;
5510: DMGetNumDS(dm, &Nds);
5511: for (n = 0; n < Nds; ++n)
5512: if (ds == dm->probs[n].ds) break;
5513: if (n >= Nds) *num = -1;
5514: else *num = n;
5515: return 0;
5516: }
5518: /*@C
5519: DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5521: Not collective
5523: Input Parameters:
5524: + dm - The `DM`
5525: . Nc - The number of components for the field
5526: . prefix - The options prefix for the output `PetscFE`, or NULL
5527: - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5529: Output Parameter:
5530: . fem - The `PetscFE`
5532: Note:
5533: This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5535: Level: intermediate
5537: .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5538: @*/
5539: PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5540: {
5541: DMPolytopeType ct;
5542: PetscInt dim, cStart;
5549: DMGetDimension(dm, &dim);
5550: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5551: DMPlexGetCellType(dm, cStart, &ct);
5552: PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem);
5553: return 0;
5554: }
5556: /*@
5557: DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5559: Collective on dm
5561: Input Parameter:
5562: . dm - The `DM`
5564: Options Database Keys:
5565: . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5567: Note:
5568: If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`.
5570: Level: intermediate
5572: .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5573: @*/
5574: PetscErrorCode DMCreateDS(DM dm)
5575: {
5576: MPI_Comm comm;
5577: PetscDS dsDef;
5578: DMLabel *labelSet;
5579: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5580: PetscBool doSetup = PETSC_TRUE, flg;
5583: if (!dm->fields) return 0;
5584: PetscObjectGetComm((PetscObject)dm, &comm);
5585: DMGetCoordinateDim(dm, &dE);
5586: /* Determine how many regions we have */
5587: PetscMalloc1(Nf, &labelSet);
5588: Nl = 0;
5589: Ndef = 0;
5590: for (f = 0; f < Nf; ++f) {
5591: DMLabel label = dm->fields[f].label;
5592: PetscInt l;
5594: #ifdef PETSC_HAVE_LIBCEED
5595: /* Move CEED context to discretizations */
5596: {
5597: PetscClassId id;
5599: PetscObjectGetClassId(dm->fields[f].disc, &id);
5600: if (id == PETSCFE_CLASSID) {
5601: Ceed ceed;
5603: DMGetCeed(dm, &ceed);
5604: PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed);
5605: }
5606: }
5607: #endif
5608: if (!label) {
5609: ++Ndef;
5610: continue;
5611: }
5612: for (l = 0; l < Nl; ++l)
5613: if (label == labelSet[l]) break;
5614: if (l < Nl) continue;
5615: labelSet[Nl++] = label;
5616: }
5617: /* Create default DS if there are no labels to intersect with */
5618: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5619: if (!dsDef && Ndef && !Nl) {
5620: IS fields;
5621: PetscInt *fld, nf;
5623: for (f = 0, nf = 0; f < Nf; ++f)
5624: if (!dm->fields[f].label) ++nf;
5626: PetscMalloc1(nf, &fld);
5627: for (f = 0, nf = 0; f < Nf; ++f)
5628: if (!dm->fields[f].label) fld[nf++] = f;
5629: ISCreate(PETSC_COMM_SELF, &fields);
5630: PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5631: ISSetType(fields, ISGENERAL);
5632: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5634: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5635: DMSetRegionDS(dm, NULL, fields, dsDef);
5636: PetscDSDestroy(&dsDef);
5637: ISDestroy(&fields);
5638: }
5639: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5640: if (dsDef) PetscDSSetCoordinateDimension(dsDef, dE);
5641: /* Intersect labels with default fields */
5642: if (Ndef && Nl) {
5643: DM plex;
5644: DMLabel cellLabel;
5645: IS fieldIS, allcellIS, defcellIS = NULL;
5646: PetscInt *fields;
5647: const PetscInt *cells;
5648: PetscInt depth, nf = 0, n, c;
5650: DMConvert(dm, DMPLEX, &plex);
5651: DMPlexGetDepth(plex, &depth);
5652: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5653: if (!allcellIS) DMGetStratumIS(plex, "depth", depth, &allcellIS);
5654: /* TODO This looks like it only works for one label */
5655: for (l = 0; l < Nl; ++l) {
5656: DMLabel label = labelSet[l];
5657: IS pointIS;
5659: ISDestroy(&defcellIS);
5660: DMLabelGetStratumIS(label, 1, &pointIS);
5661: ISDifference(allcellIS, pointIS, &defcellIS);
5662: ISDestroy(&pointIS);
5663: }
5664: ISDestroy(&allcellIS);
5666: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5667: ISGetLocalSize(defcellIS, &n);
5668: ISGetIndices(defcellIS, &cells);
5669: for (c = 0; c < n; ++c) DMLabelSetValue(cellLabel, cells[c], 1);
5670: ISRestoreIndices(defcellIS, &cells);
5671: ISDestroy(&defcellIS);
5672: DMPlexLabelComplete(plex, cellLabel);
5674: PetscMalloc1(Ndef, &fields);
5675: for (f = 0; f < Nf; ++f)
5676: if (!dm->fields[f].label) fields[nf++] = f;
5677: ISCreate(PETSC_COMM_SELF, &fieldIS);
5678: PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_");
5679: ISSetType(fieldIS, ISGENERAL);
5680: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5682: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5683: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5684: PetscDSSetCoordinateDimension(dsDef, dE);
5685: DMLabelDestroy(&cellLabel);
5686: PetscDSDestroy(&dsDef);
5687: ISDestroy(&fieldIS);
5688: DMDestroy(&plex);
5689: }
5690: /* Create label DSes
5691: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5692: */
5693: /* TODO Should check that labels are disjoint */
5694: for (l = 0; l < Nl; ++l) {
5695: DMLabel label = labelSet[l];
5696: PetscDS ds;
5697: IS fields;
5698: PetscInt *fld, nf;
5700: PetscDSCreate(PETSC_COMM_SELF, &ds);
5701: for (f = 0, nf = 0; f < Nf; ++f)
5702: if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5703: PetscMalloc1(nf, &fld);
5704: for (f = 0, nf = 0; f < Nf; ++f)
5705: if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5706: ISCreate(PETSC_COMM_SELF, &fields);
5707: PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5708: ISSetType(fields, ISGENERAL);
5709: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5710: DMSetRegionDS(dm, label, fields, ds);
5711: ISDestroy(&fields);
5712: PetscDSSetCoordinateDimension(ds, dE);
5713: {
5714: DMPolytopeType ct;
5715: PetscInt lStart, lEnd;
5716: PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive;
5718: DMLabelGetBounds(label, &lStart, &lEnd);
5719: if (lStart >= 0) {
5720: DMPlexGetCellType(dm, lStart, &ct);
5721: switch (ct) {
5722: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5723: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5724: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5725: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5726: isCohesiveLocal = PETSC_TRUE;
5727: break;
5728: default:
5729: break;
5730: }
5731: }
5732: MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm);
5733: for (f = 0, nf = 0; f < Nf; ++f) {
5734: if (label == dm->fields[f].label || !dm->fields[f].label) {
5735: if (label == dm->fields[f].label) {
5736: PetscDSSetDiscretization(ds, nf, NULL);
5737: PetscDSSetCohesive(ds, nf, isCohesive);
5738: }
5739: ++nf;
5740: }
5741: }
5742: }
5743: PetscDSDestroy(&ds);
5744: }
5745: PetscFree(labelSet);
5746: /* Set fields in DSes */
5747: for (s = 0; s < dm->Nds; ++s) {
5748: PetscDS ds = dm->probs[s].ds;
5749: IS fields = dm->probs[s].fields;
5750: const PetscInt *fld;
5751: PetscInt nf, dsnf;
5752: PetscBool isCohesive;
5754: PetscDSGetNumFields(ds, &dsnf);
5755: PetscDSIsCohesive(ds, &isCohesive);
5756: ISGetLocalSize(fields, &nf);
5757: ISGetIndices(fields, &fld);
5758: for (f = 0; f < nf; ++f) {
5759: PetscObject disc = dm->fields[fld[f]].disc;
5760: PetscBool isCohesiveField;
5761: PetscClassId id;
5763: /* Handle DS with no fields */
5764: if (dsnf) PetscDSGetCohesive(ds, f, &isCohesiveField);
5765: /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5766: if (isCohesive && !isCohesiveField) PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&disc);
5767: PetscDSSetDiscretization(ds, f, disc);
5768: /* We allow people to have placeholder fields and construct the Section by hand */
5769: PetscObjectGetClassId(disc, &id);
5770: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5771: }
5772: ISRestoreIndices(fields, &fld);
5773: }
5774: /* Allow k-jet tabulation */
5775: PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5776: if (flg) {
5777: for (s = 0; s < dm->Nds; ++s) {
5778: PetscDS ds = dm->probs[s].ds;
5779: PetscInt Nf, f;
5781: PetscDSGetNumFields(ds, &Nf);
5782: for (f = 0; f < Nf; ++f) PetscDSSetJetDegree(ds, f, k);
5783: }
5784: }
5785: /* Setup DSes */
5786: if (doSetup) {
5787: for (s = 0; s < dm->Nds; ++s) PetscDSSetUp(dm->probs[s].ds);
5788: }
5789: return 0;
5790: }
5792: /*@
5793: DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
5795: Collective on `DM`
5797: Input Parameters:
5798: + dm - The `DM`
5799: - time - The time
5801: Output Parameters:
5802: + u - The vector will be filled with exact solution values, or NULL
5803: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5805: Note:
5806: The user must call `PetscDSSetExactSolution()` before using this routine
5808: Level: developer
5810: .seealso: `PetscDSSetExactSolution()`
5811: @*/
5812: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5813: {
5814: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5815: void **ectxs;
5816: PetscInt Nf, Nds, s;
5821: DMGetNumFields(dm, &Nf);
5822: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5823: DMGetNumDS(dm, &Nds);
5824: for (s = 0; s < Nds; ++s) {
5825: PetscDS ds;
5826: DMLabel label;
5827: IS fieldIS;
5828: const PetscInt *fields, id = 1;
5829: PetscInt dsNf, f;
5831: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5832: PetscDSGetNumFields(ds, &dsNf);
5833: ISGetIndices(fieldIS, &fields);
5834: PetscArrayzero(exacts, Nf);
5835: PetscArrayzero(ectxs, Nf);
5836: if (u) {
5837: for (f = 0; f < dsNf; ++f) {
5838: const PetscInt field = fields[f];
5839: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5840: }
5841: ISRestoreIndices(fieldIS, &fields);
5842: if (label) {
5843: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5844: } else {
5845: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5846: }
5847: }
5848: if (u_t) {
5849: PetscArrayzero(exacts, Nf);
5850: PetscArrayzero(ectxs, Nf);
5851: for (f = 0; f < dsNf; ++f) {
5852: const PetscInt field = fields[f];
5853: PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5854: }
5855: ISRestoreIndices(fieldIS, &fields);
5856: if (label) {
5857: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5858: } else {
5859: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5860: }
5861: }
5862: }
5863: if (u) {
5864: PetscObjectSetName((PetscObject)u, "Exact Solution");
5865: PetscObjectSetOptionsPrefix((PetscObject)u, "exact_");
5866: }
5867: if (u_t) {
5868: PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative");
5869: PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_");
5870: }
5871: PetscFree2(exacts, ectxs);
5872: return 0;
5873: }
5875: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5876: {
5877: PetscDS dsNew;
5878: DSBoundary b;
5879: PetscInt cdim, Nf, f, d;
5880: PetscBool isCohesive;
5881: void *ctx;
5883: PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew);
5884: PetscDSCopyConstants(ds, dsNew);
5885: PetscDSCopyExactSolutions(ds, dsNew);
5886: PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5887: PetscDSCopyEquations(ds, dsNew);
5888: PetscDSGetNumFields(ds, &Nf);
5889: for (f = 0; f < Nf; ++f) {
5890: PetscDSGetContext(ds, f, &ctx);
5891: PetscDSSetContext(dsNew, f, ctx);
5892: PetscDSGetCohesive(ds, f, &isCohesive);
5893: PetscDSSetCohesive(dsNew, f, isCohesive);
5894: PetscDSGetJetDegree(ds, f, &d);
5895: PetscDSSetJetDegree(dsNew, f, d);
5896: }
5897: if (Nf) {
5898: PetscDSGetCoordinateDimension(ds, &cdim);
5899: PetscDSSetCoordinateDimension(dsNew, cdim);
5900: }
5901: PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5902: for (b = dsNew->boundary; b; b = b->next) {
5903: DMGetLabel(dm, b->lname, &b->label);
5904: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5906: }
5908: DMSetRegionDS(dm, label, fields, dsNew);
5909: PetscDSDestroy(&dsNew);
5910: return 0;
5911: }
5913: /*@
5914: DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
5916: Collective on dm
5918: Input Parameter:
5919: . dm - The `DM`
5921: Output Parameter:
5922: . newdm - The `DM`
5924: Level: advanced
5926: .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5927: @*/
5928: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5929: {
5930: PetscInt Nds, s;
5932: if (dm == newdm) return 0;
5933: DMGetNumDS(dm, &Nds);
5934: DMClearDS(newdm);
5935: for (s = 0; s < Nds; ++s) {
5936: DMLabel label;
5937: IS fields;
5938: PetscDS ds, newds;
5939: PetscInt Nbd, bd;
5941: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5942: /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5943: DMTransferDS_Internal(newdm, label, fields, ds);
5944: /* Complete new labels in the new DS */
5945: DMGetRegionDS(newdm, label, NULL, &newds);
5946: PetscDSGetNumBoundary(newds, &Nbd);
5947: for (bd = 0; bd < Nbd; ++bd) {
5948: PetscWeakForm wf;
5949: DMLabel label;
5950: PetscInt field;
5952: PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5953: PetscWeakFormReplaceLabel(wf, label);
5954: }
5955: }
5956: DMCompleteBCLabels_Internal(newdm);
5957: return 0;
5958: }
5960: /*@
5961: DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
5963: Collective on dm
5965: Input Parameter:
5966: . dm - The `DM`
5968: Output Parameter:
5969: . newdm - The `DM`
5971: Level: advanced
5973: Developer Note:
5974: Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
5976: .seealso: `DMCopyFields()`, `DMCopyDS()`
5977: @*/
5978: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5979: {
5980: DMCopyFields(dm, newdm);
5981: DMCopyDS(dm, newdm);
5982: return 0;
5983: }
5985: /*@
5986: DMGetDimension - Return the topological dimension of the `DM`
5988: Not collective
5990: Input Parameter:
5991: . dm - The `DM`
5993: Output Parameter:
5994: . dim - The topological dimension
5996: Level: beginner
5998: .seealso: `DMSetDimension()`, `DMCreate()`
5999: @*/
6000: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6001: {
6004: *dim = dm->dim;
6005: return 0;
6006: }
6008: /*@
6009: DMSetDimension - Set the topological dimension of the `DM`
6011: Collective on dm
6013: Input Parameters:
6014: + dm - The `DM`
6015: - dim - The topological dimension
6017: Level: beginner
6019: .seealso: `DMGetDimension()`, `DMCreate()`
6020: @*/
6021: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6022: {
6023: PetscDS ds;
6024: PetscInt Nds, n;
6028: dm->dim = dim;
6029: if (dm->dim >= 0) {
6030: DMGetNumDS(dm, &Nds);
6031: for (n = 0; n < Nds; ++n) {
6032: DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6033: if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
6034: }
6035: }
6036: return 0;
6037: }
6039: /*@
6040: DMGetDimPoints - Get the half-open interval for all points of a given dimension
6042: Collective on dm
6044: Input Parameters:
6045: + dm - the `DM`
6046: - dim - the dimension
6048: Output Parameters:
6049: + pStart - The first point of the given dimension
6050: - pEnd - The first point following points of the given dimension
6052: Note:
6053: The points are vertices in the Hasse diagram encoding the topology. This is explained in
6054: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6055: then the interval is empty.
6057: Level: intermediate
6059: .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6060: @*/
6061: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6062: {
6063: PetscInt d;
6066: DMGetDimension(dm, &d);
6068: PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6069: return 0;
6070: }
6072: /*@
6073: DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6075: Collective on dm
6077: Input Parameter:
6078: . dm - The original `DM`
6080: Output Parameter:
6081: . odm - The `DM` which provides the layout for output
6083: Level: intermediate
6085: Note:
6086: In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6087: conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6088: locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6090: .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6091: @*/
6092: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6093: {
6094: PetscSection section;
6095: PetscBool hasConstraints, ghasConstraints;
6099: DMGetLocalSection(dm, §ion);
6100: PetscSectionHasConstraints(section, &hasConstraints);
6101: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm));
6102: if (!ghasConstraints) {
6103: *odm = dm;
6104: return 0;
6105: }
6106: if (!dm->dmBC) {
6107: PetscSection newSection, gsection;
6108: PetscSF sf;
6110: DMClone(dm, &dm->dmBC);
6111: DMCopyDisc(dm, dm->dmBC);
6112: PetscSectionClone(section, &newSection);
6113: DMSetLocalSection(dm->dmBC, newSection);
6114: PetscSectionDestroy(&newSection);
6115: DMGetPointSF(dm->dmBC, &sf);
6116: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6117: DMSetGlobalSection(dm->dmBC, gsection);
6118: PetscSectionDestroy(&gsection);
6119: }
6120: *odm = dm->dmBC;
6121: return 0;
6122: }
6124: /*@
6125: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6127: Input Parameter:
6128: . dm - The original `DM`
6130: Output Parameters:
6131: + num - The output sequence number
6132: - val - The output sequence value
6134: Level: intermediate
6136: Note:
6137: This is intended for output that should appear in sequence, for instance
6138: a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6140: Developer Note:
6141: The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6142: not directly related to the `DM`.
6144: .seealso: `VecView()`
6145: @*/
6146: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6147: {
6149: if (num) {
6151: *num = dm->outputSequenceNum;
6152: }
6153: if (val) {
6155: *val = dm->outputSequenceVal;
6156: }
6157: return 0;
6158: }
6160: /*@
6161: DMSetOutputSequenceNumber - Set the sequence number/value for output
6163: Input Parameters:
6164: + dm - The original `DM`
6165: . num - The output sequence number
6166: - val - The output sequence value
6168: Level: intermediate
6170: Note:
6171: This is intended for output that should appear in sequence, for instance
6172: a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6174: .seealso: `VecView()`
6175: @*/
6176: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6177: {
6179: dm->outputSequenceNum = num;
6180: dm->outputSequenceVal = val;
6181: return 0;
6182: }
6184: /*@C
6185: DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6187: Input Parameters:
6188: + dm - The original `DM`
6189: . name - The sequence name
6190: - num - The output sequence number
6192: Output Parameter:
6193: . val - The output sequence value
6195: Level: intermediate
6197: Note:
6198: This is intended for output that should appear in sequence, for instance
6199: a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6201: Developer Note:
6202: It is unclear at the user API level why a `DM` is needed as input
6204: .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6205: @*/
6206: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6207: {
6208: PetscBool ishdf5;
6213: PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
6214: if (ishdf5) {
6215: #if defined(PETSC_HAVE_HDF5)
6216: PetscScalar value;
6218: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6219: *val = PetscRealPart(value);
6220: #endif
6221: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6222: return 0;
6223: }
6225: /*@
6226: DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6228: Not collective
6230: Input Parameter:
6231: . dm - The `DM`
6233: Output Parameter:
6234: . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6236: Level: beginner
6238: .seealso: `DMSetUseNatural()`, `DMCreate()`
6239: @*/
6240: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6241: {
6244: *useNatural = dm->useNatural;
6245: return 0;
6246: }
6248: /*@
6249: DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6251: Collective on dm
6253: Input Parameters:
6254: + dm - The `DM`
6255: - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6257: Note:
6258: This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6260: Level: beginner
6262: .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6263: @*/
6264: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6265: {
6268: dm->useNatural = useNatural;
6269: return 0;
6270: }
6272: /*@C
6273: DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6275: Not Collective
6277: Input Parameters:
6278: + dm - The `DM` object
6279: - name - The label name
6281: Level: intermediate
6283: .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6284: @*/
6285: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6286: {
6287: PetscBool flg;
6288: DMLabel label;
6292: DMHasLabel(dm, name, &flg);
6293: if (!flg) {
6294: DMLabelCreate(PETSC_COMM_SELF, name, &label);
6295: DMAddLabel(dm, label);
6296: DMLabelDestroy(&label);
6297: }
6298: return 0;
6299: }
6301: /*@C
6302: DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6304: Not Collective
6306: Input Parameters:
6307: + dm - The `DM` object
6308: . l - The index for the label
6309: - name - The label name
6311: Level: intermediate
6313: .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6314: @*/
6315: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6316: {
6317: DMLabelLink orig, prev = NULL;
6318: DMLabel label;
6319: PetscInt Nl, m;
6320: PetscBool flg, match;
6321: const char *lname;
6325: DMHasLabel(dm, name, &flg);
6326: if (!flg) {
6327: DMLabelCreate(PETSC_COMM_SELF, name, &label);
6328: DMAddLabel(dm, label);
6329: DMLabelDestroy(&label);
6330: }
6331: DMGetNumLabels(dm, &Nl);
6333: for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6334: PetscObjectGetName((PetscObject)orig->label, &lname);
6335: PetscStrcmp(name, lname, &match);
6336: if (match) break;
6337: }
6338: if (m == l) return 0;
6339: if (!m) dm->labels = orig->next;
6340: else prev->next = orig->next;
6341: if (!l) {
6342: orig->next = dm->labels;
6343: dm->labels = orig;
6344: } else {
6345: for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6346: ;
6347: orig->next = prev->next;
6348: prev->next = orig;
6349: }
6350: return 0;
6351: }
6353: /*@C
6354: DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6356: Not Collective
6358: Input Parameters:
6359: + dm - The `DM` object
6360: . name - The label name
6361: - point - The mesh point
6363: Output Parameter:
6364: . value - The label value for this point, or -1 if the point is not in the label
6366: Level: beginner
6368: .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6369: @*/
6370: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6371: {
6372: DMLabel label;
6376: DMGetLabel(dm, name, &label);
6378: DMLabelGetValue(label, point, value);
6379: return 0;
6380: }
6382: /*@C
6383: DMSetLabelValue - Add a point to a `DMLabel` with given value
6385: Not Collective
6387: Input Parameters:
6388: + dm - The `DM` object
6389: . name - The label name
6390: . point - The mesh point
6391: - value - The label value for this point
6393: Output Parameter:
6395: Level: beginner
6397: .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6398: @*/
6399: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6400: {
6401: DMLabel label;
6405: DMGetLabel(dm, name, &label);
6406: if (!label) {
6407: DMCreateLabel(dm, name);
6408: DMGetLabel(dm, name, &label);
6409: }
6410: DMLabelSetValue(label, point, value);
6411: return 0;
6412: }
6414: /*@C
6415: DMClearLabelValue - Remove a point from a `DMLabel` with given value
6417: Not Collective
6419: Input Parameters:
6420: + dm - The `DM` object
6421: . name - The label name
6422: . point - The mesh point
6423: - value - The label value for this point
6425: Level: beginner
6427: .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6428: @*/
6429: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6430: {
6431: DMLabel label;
6435: DMGetLabel(dm, name, &label);
6436: if (!label) return 0;
6437: DMLabelClearValue(label, point, value);
6438: return 0;
6439: }
6441: /*@C
6442: DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6444: Not Collective
6446: Input Parameters:
6447: + dm - The `DM` object
6448: - name - The label name
6450: Output Parameter:
6451: . size - The number of different integer ids, or 0 if the label does not exist
6453: Level: beginner
6455: Developer Note:
6456: This should be renamed to something like `DMGetLabelNumValues()` or removed.
6458: .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6459: @*/
6460: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6461: {
6462: DMLabel label;
6467: DMGetLabel(dm, name, &label);
6468: *size = 0;
6469: if (!label) return 0;
6470: DMLabelGetNumValues(label, size);
6471: return 0;
6472: }
6474: /*@C
6475: DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6477: Not Collective
6479: Input Parameters:
6480: + mesh - The `DM` object
6481: - name - The label name
6483: Output Parameter:
6484: . ids - The integer ids, or NULL if the label does not exist
6486: Level: beginner
6488: .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6489: @*/
6490: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6491: {
6492: DMLabel label;
6497: DMGetLabel(dm, name, &label);
6498: *ids = NULL;
6499: if (label) {
6500: DMLabelGetValueIS(label, ids);
6501: } else {
6502: /* returning an empty IS */
6503: ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids);
6504: }
6505: return 0;
6506: }
6508: /*@C
6509: DMGetStratumSize - Get the number of points in a label stratum
6511: Not Collective
6513: Input Parameters:
6514: + dm - The `DM` object
6515: . name - The label name
6516: - value - The stratum value
6518: Output Parameter:
6519: . size - The number of points, also called the stratum size
6521: Level: beginner
6523: .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6524: @*/
6525: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6526: {
6527: DMLabel label;
6532: DMGetLabel(dm, name, &label);
6533: *size = 0;
6534: if (!label) return 0;
6535: DMLabelGetStratumSize(label, value, size);
6536: return 0;
6537: }
6539: /*@C
6540: DMGetStratumIS - Get the points in a label stratum
6542: Not Collective
6544: Input Parameters:
6545: + dm - The `DM` object
6546: . name - The label name
6547: - value - The stratum value
6549: Output Parameter:
6550: . points - The stratum points, or NULL if the label does not exist or does not have that value
6552: Level: beginner
6554: .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6555: @*/
6556: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6557: {
6558: DMLabel label;
6563: DMGetLabel(dm, name, &label);
6564: *points = NULL;
6565: if (!label) return 0;
6566: DMLabelGetStratumIS(label, value, points);
6567: return 0;
6568: }
6570: /*@C
6571: DMSetStratumIS - Set the points in a label stratum
6573: Not Collective
6575: Input Parameters:
6576: + dm - The `DM` object
6577: . name - The label name
6578: . value - The stratum value
6579: - points - The stratum points
6581: Level: beginner
6583: .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6584: @*/
6585: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6586: {
6587: DMLabel label;
6592: DMGetLabel(dm, name, &label);
6593: if (!label) return 0;
6594: DMLabelSetStratumIS(label, value, points);
6595: return 0;
6596: }
6598: /*@C
6599: DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
6601: Not Collective
6603: Input Parameters:
6604: + dm - The `DM` object
6605: . name - The label name
6606: - value - The label value for this point
6608: Output Parameter:
6610: Level: beginner
6612: .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6613: @*/
6614: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6615: {
6616: DMLabel label;
6620: DMGetLabel(dm, name, &label);
6621: if (!label) return 0;
6622: DMLabelClearStratum(label, value);
6623: return 0;
6624: }
6626: /*@
6627: DMGetNumLabels - Return the number of labels defined by on the `DM`
6629: Not Collective
6631: Input Parameter:
6632: . dm - The `DM` object
6634: Output Parameter:
6635: . numLabels - the number of Labels
6637: Level: intermediate
6639: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6640: @*/
6641: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6642: {
6643: DMLabelLink next = dm->labels;
6644: PetscInt n = 0;
6648: while (next) {
6649: ++n;
6650: next = next->next;
6651: }
6652: *numLabels = n;
6653: return 0;
6654: }
6656: /*@C
6657: DMGetLabelName - Return the name of nth label
6659: Not Collective
6661: Input Parameters:
6662: + dm - The `DM` object
6663: - n - the label number
6665: Output Parameter:
6666: . name - the label name
6668: Level: intermediate
6670: Developer Note:
6671: Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
6673: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6674: @*/
6675: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6676: {
6677: DMLabelLink next = dm->labels;
6678: PetscInt l = 0;
6682: while (next) {
6683: if (l == n) {
6684: PetscObjectGetName((PetscObject)next->label, name);
6685: return 0;
6686: }
6687: ++l;
6688: next = next->next;
6689: }
6690: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6691: }
6693: /*@C
6694: DMHasLabel - Determine whether the `DM` has a label of a given name
6696: Not Collective
6698: Input Parameters:
6699: + dm - The `DM` object
6700: - name - The label name
6702: Output Parameter:
6703: . hasLabel - `PETSC_TRUE` if the label is present
6705: Level: intermediate
6707: .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6708: @*/
6709: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6710: {
6711: DMLabelLink next = dm->labels;
6712: const char *lname;
6717: *hasLabel = PETSC_FALSE;
6718: while (next) {
6719: PetscObjectGetName((PetscObject)next->label, &lname);
6720: PetscStrcmp(name, lname, hasLabel);
6721: if (*hasLabel) break;
6722: next = next->next;
6723: }
6724: return 0;
6725: }
6727: /*@C
6728: DMGetLabel - Return the label of a given name, or NULL, from a `DM`
6730: Not Collective
6732: Input Parameters:
6733: + dm - The `DM` object
6734: - name - The label name
6736: Output Parameter:
6737: . label - The `DMLabel`, or NULL if the label is absent
6739: Default labels in a `DMPLEX`:
6740: + "depth" - Holds the depth (co-dimension) of each mesh point
6741: . "celltype" - Holds the topological type of each cell
6742: . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6743: . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
6744: . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
6745: - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6747: Level: intermediate
6749: .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6750: @*/
6751: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6752: {
6753: DMLabelLink next = dm->labels;
6754: PetscBool hasLabel;
6755: const char *lname;
6760: *label = NULL;
6761: while (next) {
6762: PetscObjectGetName((PetscObject)next->label, &lname);
6763: PetscStrcmp(name, lname, &hasLabel);
6764: if (hasLabel) {
6765: *label = next->label;
6766: break;
6767: }
6768: next = next->next;
6769: }
6770: return 0;
6771: }
6773: /*@C
6774: DMGetLabelByNum - Return the nth label on a `DM`
6776: Not Collective
6778: Input Parameters:
6779: + dm - The `DM` object
6780: - n - the label number
6782: Output Parameter:
6783: . label - the label
6785: Level: intermediate
6787: .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6788: @*/
6789: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6790: {
6791: DMLabelLink next = dm->labels;
6792: PetscInt l = 0;
6796: while (next) {
6797: if (l == n) {
6798: *label = next->label;
6799: return 0;
6800: }
6801: ++l;
6802: next = next->next;
6803: }
6804: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6805: }
6807: /*@C
6808: DMAddLabel - Add the label to this `DM`
6810: Not Collective
6812: Input Parameters:
6813: + dm - The `DM` object
6814: - label - The `DMLabel`
6816: Level: developer
6818: .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6819: @*/
6820: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6821: {
6822: DMLabelLink l, *p, tmpLabel;
6823: PetscBool hasLabel;
6824: const char *lname;
6825: PetscBool flg;
6828: PetscObjectGetName((PetscObject)label, &lname);
6829: DMHasLabel(dm, lname, &hasLabel);
6831: PetscCalloc1(1, &tmpLabel);
6832: tmpLabel->label = label;
6833: tmpLabel->output = PETSC_TRUE;
6834: for (p = &dm->labels; (l = *p); p = &l->next) { }
6835: *p = tmpLabel;
6836: PetscObjectReference((PetscObject)label);
6837: PetscStrcmp(lname, "depth", &flg);
6838: if (flg) dm->depthLabel = label;
6839: PetscStrcmp(lname, "celltype", &flg);
6840: if (flg) dm->celltypeLabel = label;
6841: return 0;
6842: }
6844: /*@C
6845: DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
6847: Not Collective
6849: Input Parameters:
6850: + dm - The `DM` object
6851: - label - The `DMLabel`, having the same name, to substitute
6853: Default labels in a `DMPLEX`:
6854: + "depth" - Holds the depth (co-dimension) of each mesh point
6855: . "celltype" - Holds the topological type of each cell
6856: . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6857: . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
6858: . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
6859: - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6861: Level: intermediate
6863: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6864: @*/
6865: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
6866: {
6867: DMLabelLink next = dm->labels;
6868: PetscBool hasLabel, flg;
6869: const char *name, *lname;
6873: PetscObjectGetName((PetscObject)label, &name);
6874: while (next) {
6875: PetscObjectGetName((PetscObject)next->label, &lname);
6876: PetscStrcmp(name, lname, &hasLabel);
6877: if (hasLabel) {
6878: PetscObjectReference((PetscObject)label);
6879: PetscStrcmp(lname, "depth", &flg);
6880: if (flg) dm->depthLabel = label;
6881: PetscStrcmp(lname, "celltype", &flg);
6882: if (flg) dm->celltypeLabel = label;
6883: DMLabelDestroy(&next->label);
6884: next->label = label;
6885: break;
6886: }
6887: next = next->next;
6888: }
6889: return 0;
6890: }
6892: /*@C
6893: DMRemoveLabel - Remove the label given by name from this `DM`
6895: Not Collective
6897: Input Parameters:
6898: + dm - The `DM` object
6899: - name - The label name
6901: Output Parameter:
6902: . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the
6903: caller is responsible for calling `DMLabelDestroy()`.
6905: Level: developer
6907: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
6908: @*/
6909: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6910: {
6911: DMLabelLink link, *pnext;
6912: PetscBool hasLabel;
6913: const char *lname;
6917: if (label) {
6919: *label = NULL;
6920: }
6921: for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6922: PetscObjectGetName((PetscObject)link->label, &lname);
6923: PetscStrcmp(name, lname, &hasLabel);
6924: if (hasLabel) {
6925: *pnext = link->next; /* Remove from list */
6926: PetscStrcmp(name, "depth", &hasLabel);
6927: if (hasLabel) dm->depthLabel = NULL;
6928: PetscStrcmp(name, "celltype", &hasLabel);
6929: if (hasLabel) dm->celltypeLabel = NULL;
6930: if (label) *label = link->label;
6931: else DMLabelDestroy(&link->label);
6932: PetscFree(link);
6933: break;
6934: }
6935: }
6936: return 0;
6937: }
6939: /*@
6940: DMRemoveLabelBySelf - Remove the label from this `DM`
6942: Not Collective
6944: Input Parameters:
6945: + dm - The `DM` object
6946: . label - The `DMLabel` to be removed from the `DM`
6947: - failNotFound - Should it fail if the label is not found in the DM?
6949: Level: developer
6951: Note:
6952: Only exactly the same instance is removed if found, name match is ignored.
6953: If the `DM` has an exclusive reference to the label, the label gets destroyed and
6954: *label nullified.
6956: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
6957: @*/
6958: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
6959: {
6960: DMLabelLink link, *pnext;
6961: PetscBool hasLabel = PETSC_FALSE;
6965: if (!*label && !failNotFound) return 0;
6968: for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6969: if (*label == link->label) {
6970: hasLabel = PETSC_TRUE;
6971: *pnext = link->next; /* Remove from list */
6972: if (*label == dm->depthLabel) dm->depthLabel = NULL;
6973: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
6974: if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
6975: DMLabelDestroy(&link->label);
6976: PetscFree(link);
6977: break;
6978: }
6979: }
6981: return 0;
6982: }
6984: /*@C
6985: DMGetLabelOutput - Get the output flag for a given label
6987: Not Collective
6989: Input Parameters:
6990: + dm - The `DM` object
6991: - name - The label name
6993: Output Parameter:
6994: . output - The flag for output
6996: Level: developer
6998: .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6999: @*/
7000: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7001: {
7002: DMLabelLink next = dm->labels;
7003: const char *lname;
7008: while (next) {
7009: PetscBool flg;
7011: PetscObjectGetName((PetscObject)next->label, &lname);
7012: PetscStrcmp(name, lname, &flg);
7013: if (flg) {
7014: *output = next->output;
7015: return 0;
7016: }
7017: next = next->next;
7018: }
7019: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7020: }
7022: /*@C
7023: DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7025: Not Collective
7027: Input Parameters:
7028: + dm - The `DM` object
7029: . name - The label name
7030: - output - `PETSC_TRUE` to save the label to the viewer
7032: Level: developer
7034: .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7035: @*/
7036: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7037: {
7038: DMLabelLink next = dm->labels;
7039: const char *lname;
7043: while (next) {
7044: PetscBool flg;
7046: PetscObjectGetName((PetscObject)next->label, &lname);
7047: PetscStrcmp(name, lname, &flg);
7048: if (flg) {
7049: next->output = output;
7050: return 0;
7051: }
7052: next = next->next;
7053: }
7054: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7055: }
7057: /*@
7058: DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7060: Collective on dmA
7062: Input Parameters:
7063: + dmA - The `DM` object with initial labels
7064: . dmB - The `DM` object to which labels are copied
7065: . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7066: . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7067: - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7069: Level: intermediate
7071: Note:
7072: This is typically used when interpolating or otherwise adding to a mesh, or testing.
7074: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7075: @*/
7076: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7077: {
7078: DMLabel label, labelNew, labelOld;
7079: const char *name;
7080: PetscBool flg;
7081: DMLabelLink link;
7088: if (dmA == dmB) return 0;
7089: for (link = dmA->labels; link; link = link->next) {
7090: label = link->label;
7091: PetscObjectGetName((PetscObject)label, &name);
7092: if (!all) {
7093: PetscStrcmp(name, "depth", &flg);
7094: if (flg) continue;
7095: PetscStrcmp(name, "dim", &flg);
7096: if (flg) continue;
7097: PetscStrcmp(name, "celltype", &flg);
7098: if (flg) continue;
7099: }
7100: DMGetLabel(dmB, name, &labelOld);
7101: if (labelOld) {
7102: switch (emode) {
7103: case DM_COPY_LABELS_KEEP:
7104: continue;
7105: case DM_COPY_LABELS_REPLACE:
7106: DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
7107: break;
7108: case DM_COPY_LABELS_FAIL:
7109: SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7110: default:
7111: SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7112: }
7113: }
7114: if (mode == PETSC_COPY_VALUES) {
7115: DMLabelDuplicate(label, &labelNew);
7116: } else {
7117: labelNew = label;
7118: }
7119: DMAddLabel(dmB, labelNew);
7120: if (mode == PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
7121: }
7122: return 0;
7123: }
7125: /*@C
7126: DMCompareLabels - Compare labels of two `DMPLEX` meshes
7128: Collective
7130: Input Parameters:
7131: + dm0 - First `DM` object
7132: - dm1 - Second `DM` object
7134: Output Parameters
7135: + equal - (Optional) Flag whether labels of dm0 and dm1 are the same
7136: - message - (Optional) Message describing the difference, or NULL if there is no difference
7138: Level: intermediate
7140: Notes:
7141: The output flag equal will be the same on all processes.
7143: If equal is passed as NULL and difference is found, an error is thrown on all processes.
7145: Make sure to pass equal is NULL on all processes or none of them.
7147: The output message is set independently on each rank.
7149: message must be freed with `PetscFree()`
7151: If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner.
7153: Make sure to pass message as NULL on all processes or no processes.
7155: Labels are matched by name. If the number of labels and their names are equal,
7156: `DMLabelCompare()` is used to compare each pair of labels with the same name.
7158: Fortran Note:
7159: This function is not available from Fortran.
7161: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7162: @*/
7163: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7164: {
7165: PetscInt n, i;
7166: char msg[PETSC_MAX_PATH_LEN] = "";
7167: PetscBool eq;
7168: MPI_Comm comm;
7169: PetscMPIInt rank;
7176: PetscObjectGetComm((PetscObject)dm0, &comm);
7177: MPI_Comm_rank(comm, &rank);
7178: {
7179: PetscInt n1;
7181: DMGetNumLabels(dm0, &n);
7182: DMGetNumLabels(dm1, &n1);
7183: eq = (PetscBool)(n == n1);
7184: if (!eq) PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1);
7185: MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7186: if (!eq) goto finish;
7187: }
7188: for (i = 0; i < n; i++) {
7189: DMLabel l0, l1;
7190: const char *name;
7191: char *msgInner;
7193: /* Ignore label order */
7194: DMGetLabelByNum(dm0, i, &l0);
7195: PetscObjectGetName((PetscObject)l0, &name);
7196: DMGetLabel(dm1, name, &l1);
7197: if (!l1) {
7198: PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i);
7199: eq = PETSC_FALSE;
7200: break;
7201: }
7202: DMLabelCompare(comm, l0, l1, &eq, &msgInner);
7203: PetscStrncpy(msg, msgInner, sizeof(msg));
7204: PetscFree(msgInner);
7205: if (!eq) break;
7206: }
7207: MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7208: finish:
7209: /* If message output arg not set, print to stderr */
7210: if (message) {
7211: *message = NULL;
7212: if (msg[0]) PetscStrallocpy(msg, message);
7213: } else {
7214: if (msg[0]) PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
7215: PetscSynchronizedFlush(comm, PETSC_STDERR);
7216: }
7217: /* If same output arg not ser and labels are not equal, throw error */
7218: if (equal) *equal = eq;
7220: return 0;
7221: }
7223: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7224: {
7226: if (!*label) {
7227: DMCreateLabel(dm, name);
7228: DMGetLabel(dm, name, label);
7229: }
7230: DMLabelSetValue(*label, point, value);
7231: return 0;
7232: }
7234: /*
7235: Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7236: like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7237: (label, id) pair in the DM.
7239: However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7240: each label.
7241: */
7242: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7243: {
7244: DMUniversalLabel ul;
7245: PetscBool *active;
7246: PetscInt pStart, pEnd, p, Nl, l, m;
7248: PetscMalloc1(1, &ul);
7249: DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
7250: DMGetNumLabels(dm, &Nl);
7251: PetscCalloc1(Nl, &active);
7252: ul->Nl = 0;
7253: for (l = 0; l < Nl; ++l) {
7254: PetscBool isdepth, iscelltype;
7255: const char *name;
7257: DMGetLabelName(dm, l, &name);
7258: PetscStrncmp(name, "depth", 6, &isdepth);
7259: PetscStrncmp(name, "celltype", 9, &iscelltype);
7260: active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7261: if (active[l]) ++ul->Nl;
7262: }
7263: PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks);
7264: ul->Nv = 0;
7265: for (l = 0, m = 0; l < Nl; ++l) {
7266: DMLabel label;
7267: PetscInt nv;
7268: const char *name;
7270: if (!active[l]) continue;
7271: DMGetLabelName(dm, l, &name);
7272: DMGetLabelByNum(dm, l, &label);
7273: DMLabelGetNumValues(label, &nv);
7274: PetscStrallocpy(name, &ul->names[m]);
7275: ul->indices[m] = l;
7276: ul->Nv += nv;
7277: ul->offsets[m + 1] = nv;
7278: ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1));
7279: ++m;
7280: }
7281: for (l = 1; l <= ul->Nl; ++l) {
7282: ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7283: ul->bits[l] = ul->bits[l - 1] + ul->bits[l];
7284: }
7285: for (l = 0; l < ul->Nl; ++l) {
7286: PetscInt b;
7288: ul->masks[l] = 0;
7289: for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7290: }
7291: PetscMalloc1(ul->Nv, &ul->values);
7292: for (l = 0, m = 0; l < Nl; ++l) {
7293: DMLabel label;
7294: IS valueIS;
7295: const PetscInt *varr;
7296: PetscInt nv, v;
7298: if (!active[l]) continue;
7299: DMGetLabelByNum(dm, l, &label);
7300: DMLabelGetNumValues(label, &nv);
7301: DMLabelGetValueIS(label, &valueIS);
7302: ISGetIndices(valueIS, &varr);
7303: for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7304: ISRestoreIndices(valueIS, &varr);
7305: ISDestroy(&valueIS);
7306: PetscSortInt(nv, &ul->values[ul->offsets[m]]);
7307: ++m;
7308: }
7309: DMPlexGetChart(dm, &pStart, &pEnd);
7310: for (p = pStart; p < pEnd; ++p) {
7311: PetscInt uval = 0;
7312: PetscBool marked = PETSC_FALSE;
7314: for (l = 0, m = 0; l < Nl; ++l) {
7315: DMLabel label;
7316: PetscInt val, defval, loc, nv;
7318: if (!active[l]) continue;
7319: DMGetLabelByNum(dm, l, &label);
7320: DMLabelGetValue(label, p, &val);
7321: DMLabelGetDefaultValue(label, &defval);
7322: if (val == defval) {
7323: ++m;
7324: continue;
7325: }
7326: nv = ul->offsets[m + 1] - ul->offsets[m];
7327: marked = PETSC_TRUE;
7328: PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
7330: uval += (loc + 1) << ul->bits[m];
7331: ++m;
7332: }
7333: if (marked) DMLabelSetValue(ul->label, p, uval);
7334: }
7335: PetscFree(active);
7336: *universal = ul;
7337: return 0;
7338: }
7340: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7341: {
7342: PetscInt l;
7344: for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
7345: DMLabelDestroy(&(*universal)->label);
7346: PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
7347: PetscFree((*universal)->values);
7348: PetscFree(*universal);
7349: *universal = NULL;
7350: return 0;
7351: }
7353: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7354: {
7356: *ulabel = ul->label;
7357: return 0;
7358: }
7360: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7361: {
7362: PetscInt Nl = ul->Nl, l;
7365: for (l = 0; l < Nl; ++l) {
7366: if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
7367: else DMCreateLabel(dm, ul->names[l]);
7368: }
7369: if (preserveOrder) {
7370: for (l = 0; l < ul->Nl; ++l) {
7371: const char *name;
7372: PetscBool match;
7374: DMGetLabelName(dm, ul->indices[l], &name);
7375: PetscStrcmp(name, ul->names[l], &match);
7377: }
7378: }
7379: return 0;
7380: }
7382: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7383: {
7384: PetscInt l;
7386: for (l = 0; l < ul->Nl; ++l) {
7387: DMLabel label;
7388: PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7390: if (lval) {
7391: if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
7392: else DMGetLabel(dm, ul->names[l], &label);
7393: DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]);
7394: }
7395: }
7396: return 0;
7397: }
7399: /*@
7400: DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7402: Not collective
7404: Input Parameter:
7405: . dm - The `DM` object
7407: Output Parameter:
7408: . cdm - The coarse `DM`
7410: Level: intermediate
7412: .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7413: @*/
7414: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7415: {
7418: *cdm = dm->coarseMesh;
7419: return 0;
7420: }
7422: /*@
7423: DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7425: Input Parameters:
7426: + dm - The `DM` object
7427: - cdm - The coarse `DM`
7429: Level: intermediate
7431: Note:
7432: Normally this is set automatically by `DMRefine()`
7434: .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7435: @*/
7436: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7437: {
7440: if (dm == cdm) cdm = NULL;
7441: PetscObjectReference((PetscObject)cdm);
7442: DMDestroy(&dm->coarseMesh);
7443: dm->coarseMesh = cdm;
7444: return 0;
7445: }
7447: /*@
7448: DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7450: Input Parameter:
7451: . dm - The `DM` object
7453: Output Parameter:
7454: . fdm - The fine `DM`
7456: Level: intermediate
7458: .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7459: @*/
7460: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7461: {
7464: *fdm = dm->fineMesh;
7465: return 0;
7466: }
7468: /*@
7469: DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7471: Input Parameters:
7472: + dm - The `DM` object
7473: - fdm - The fine `DM`
7475: Level: developer
7477: Note:
7478: Normally this is set automatically by `DMCoarsen()`
7480: .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7481: @*/
7482: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7483: {
7486: if (dm == fdm) fdm = NULL;
7487: PetscObjectReference((PetscObject)fdm);
7488: DMDestroy(&dm->fineMesh);
7489: dm->fineMesh = fdm;
7490: return 0;
7491: }
7493: /*@C
7494: DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7496: Collective on dm
7498: Input Parameters:
7499: + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
7500: . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7501: . name - The BC name
7502: . label - The label defining constrained points
7503: . Nv - The number of `DMLabel` values for constrained points
7504: . values - An array of values for constrained points
7505: . field - The field to constrain
7506: . Nc - The number of constrained field components (0 will constrain all fields)
7507: . comps - An array of constrained component numbers
7508: . bcFunc - A pointwise function giving boundary values
7509: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7510: - ctx - An optional user context for bcFunc
7512: Output Parameter:
7513: . bd - (Optional) Boundary number
7515: Options Database Keys:
7516: + -bc_<boundary name> <num> - Overrides the boundary ids
7517: - -bc_<boundary name>_comp <num> - Overrides the boundary components
7519: Notes:
7520: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:
7522: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7524: If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:
7526: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7527: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7528: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7529: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
7531: + dim - the spatial dimension
7532: . Nf - the number of fields
7533: . uOff - the offset into u[] and u_t[] for each field
7534: . uOff_x - the offset into u_x[] for each field
7535: . u - each field evaluated at the current point
7536: . u_t - the time derivative of each field evaluated at the current point
7537: . u_x - the gradient of each field evaluated at the current point
7538: . aOff - the offset into a[] and a_t[] for each auxiliary field
7539: . aOff_x - the offset into a_x[] for each auxiliary field
7540: . a - each auxiliary field evaluated at the current point
7541: . a_t - the time derivative of each auxiliary field evaluated at the current point
7542: . a_x - the gradient of auxiliary each field evaluated at the current point
7543: . t - current time
7544: . x - coordinates of the current point
7545: . numConstants - number of constant parameters
7546: . constants - constant parameters
7547: - bcval - output values at the current point
7549: Level: intermediate
7551: .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7552: @*/
7553: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
7554: {
7555: PetscDS ds;
7564: DMGetDS(dm, &ds);
7565: /* Complete label */
7566: if (label) {
7567: PetscObject obj;
7568: PetscClassId id;
7570: DMGetField(dm, field, NULL, &obj);
7571: PetscObjectGetClassId(obj, &id);
7572: if (id == PETSCFE_CLASSID) {
7573: DM plex;
7575: DMConvert(dm, DMPLEX, &plex);
7576: if (plex) DMPlexLabelComplete(plex, label);
7577: DMDestroy(&plex);
7578: }
7579: }
7580: PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
7581: return 0;
7582: }
7584: /* TODO Remove this since now the structures are the same */
7585: static PetscErrorCode DMPopulateBoundary(DM dm)
7586: {
7587: PetscDS ds;
7588: DMBoundary *lastnext;
7589: DSBoundary dsbound;
7591: DMGetDS(dm, &ds);
7592: dsbound = ds->boundary;
7593: if (dm->boundary) {
7594: DMBoundary next = dm->boundary;
7596: /* quick check to see if the PetscDS has changed */
7597: if (next->dsboundary == dsbound) return 0;
7598: /* the PetscDS has changed: tear down and rebuild */
7599: while (next) {
7600: DMBoundary b = next;
7602: next = b->next;
7603: PetscFree(b);
7604: }
7605: dm->boundary = NULL;
7606: }
7608: lastnext = &(dm->boundary);
7609: while (dsbound) {
7610: DMBoundary dmbound;
7612: PetscNew(&dmbound);
7613: dmbound->dsboundary = dsbound;
7614: dmbound->label = dsbound->label;
7615: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7616: *lastnext = dmbound;
7617: lastnext = &(dmbound->next);
7618: dsbound = dsbound->next;
7619: }
7620: return 0;
7621: }
7623: /* TODO: missing manual page */
7624: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7625: {
7626: DMBoundary b;
7630: *isBd = PETSC_FALSE;
7631: DMPopulateBoundary(dm);
7632: b = dm->boundary;
7633: while (b && !(*isBd)) {
7634: DMLabel label = b->label;
7635: DSBoundary dsb = b->dsboundary;
7636: PetscInt i;
7638: if (label) {
7639: for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
7640: }
7641: b = b->next;
7642: }
7643: return 0;
7644: }
7646: /*@C
7647: DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
7649: Collective on dm
7651: Input Parameters:
7652: + dm - The `DM`
7653: . time - The time
7654: . funcs - The coordinate functions to evaluate, one per field
7655: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
7656: - mode - The insertion mode for values
7658: Output Parameter:
7659: . X - vector
7661: Calling sequence of func:
7662: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7664: + dim - The spatial dimension
7665: . time - The time at which to sample
7666: . x - The coordinates
7667: . Nc - The number of components
7668: . u - The output field values
7669: - ctx - optional user-defined function context
7671: Level: developer
7673: Developer Notes:
7674: This API is specific to only particular usage of `DM`
7676: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7678: .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7679: @*/
7680: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7681: {
7682: Vec localX;
7685: DMGetLocalVector(dm, &localX);
7686: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7687: DMLocalToGlobalBegin(dm, localX, mode, X);
7688: DMLocalToGlobalEnd(dm, localX, mode, X);
7689: DMRestoreLocalVector(dm, &localX);
7690: return 0;
7691: }
7693: /*@C
7694: DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
7696: Not collective
7698: Input Parameters:
7699: + dm - The `DM`
7700: . time - The time
7701: . funcs - The coordinate functions to evaluate, one per field
7702: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
7703: - mode - The insertion mode for values
7705: Output Parameter:
7706: . localX - vector
7708: Calling sequence of func:
7709: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7711: + dim - The spatial dimension
7712: . x - The coordinates
7713: . Nc - The number of components
7714: . u - The output field values
7715: - ctx - optional user-defined function context
7717: Level: developer
7719: Developer Notes:
7720: This API is specific to only particular usage of `DM`
7722: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7724: .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7725: @*/
7726: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7727: {
7730: (dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX);
7731: return 0;
7732: }
7734: /*@C
7735: DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.
7737: Collective on dm
7739: Input Parameters:
7740: + dm - The `DM`
7741: . time - The time
7742: . label - The `DMLabel` selecting the portion of the mesh for projection
7743: . funcs - The coordinate functions to evaluate, one per field
7744: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null.
7745: - mode - The insertion mode for values
7747: Output Parameter:
7748: . X - vector
7750: Calling sequence of func:
7751: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7753: + dim - The spatial dimension
7754: . x - The coordinates
7755: . Nc - The number of components
7756: . u - The output field values
7757: - ctx - optional user-defined function context
7759: Level: developer
7761: Developer Notes:
7762: This API is specific to only particular usage of `DM`
7764: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7766: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
7767: @*/
7768: 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)
7769: {
7770: Vec localX;
7773: DMGetLocalVector(dm, &localX);
7774: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7775: DMLocalToGlobalBegin(dm, localX, mode, X);
7776: DMLocalToGlobalEnd(dm, localX, mode, X);
7777: DMRestoreLocalVector(dm, &localX);
7778: return 0;
7779: }
7781: /*@C
7782: DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.
7784: Not collective
7786: Input Parameters:
7787: + dm - The `DM`
7788: . time - The time
7789: . label - The `DMLabel` selecting the portion of the mesh for projection
7790: . funcs - The coordinate functions to evaluate, one per field
7791: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
7792: - mode - The insertion mode for values
7794: Output Parameter:
7795: . localX - vector
7797: Calling sequence of func:
7798: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7800: + dim - The spatial dimension
7801: . x - The coordinates
7802: . Nc - The number of components
7803: . u - The output field values
7804: - ctx - optional user-defined function context
7806: Level: developer
7808: Developer Notes:
7809: This API is specific to only particular usage of `DM`
7811: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7813: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7814: @*/
7815: 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)
7816: {
7819: (dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7820: return 0;
7821: }
7823: /*@C
7824: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.
7826: Not collective
7828: Input Parameters:
7829: + dm - The `DM`
7830: . time - The time
7831: . localU - The input field vector
7832: . funcs - The functions to evaluate, one per field
7833: - mode - The insertion mode for values
7835: Output Parameter:
7836: . localX - The output vector
7838: Calling sequence of func:
7839: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7840: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7841: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7842: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7844: + dim - The spatial dimension
7845: . Nf - The number of input fields
7846: . NfAux - The number of input auxiliary fields
7847: . uOff - The offset of each field in u[]
7848: . uOff_x - The offset of each field in u_x[]
7849: . u - The field values at this point in space
7850: . u_t - The field time derivative at this point in space (or NULL)
7851: . u_x - The field derivatives at this point in space
7852: . aOff - The offset of each auxiliary field in u[]
7853: . aOff_x - The offset of each auxiliary field in u_x[]
7854: . a - The auxiliary field values at this point in space
7855: . a_t - The auxiliary field time derivative at this point in space (or NULL)
7856: . a_x - The auxiliary field derivatives at this point in space
7857: . t - The current time
7858: . x - The coordinates of this point
7859: . numConstants - The number of constants
7860: . constants - The value of each constant
7861: - f - The value of the function at this point in space
7863: Note:
7864: There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
7865: 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
7866: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7867: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
7869: Level: intermediate
7871: Developer Notes:
7872: This API is specific to only particular usage of `DM`
7874: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7876: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7877: @*/
7878: PetscErrorCode 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)
7879: {
7883: (dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX);
7884: return 0;
7885: }
7887: /*@C
7888: 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.
7890: Not collective
7892: Input Parameters:
7893: + dm - The `DM`
7894: . time - The time
7895: . label - The `DMLabel` marking the portion of the domain to output
7896: . numIds - The number of label ids to use
7897: . ids - The label ids to use for marking
7898: . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7899: . comps - The components to set in the output, or NULL for all components
7900: . localU - The input field vector
7901: . funcs - The functions to evaluate, one per field
7902: - mode - The insertion mode for values
7904: Output Parameter:
7905: . localX - The output vector
7907: Calling sequence of func:
7908: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7909: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7910: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7911: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7913: + dim - The spatial dimension
7914: . Nf - The number of input fields
7915: . NfAux - The number of input auxiliary fields
7916: . uOff - The offset of each field in u[]
7917: . uOff_x - The offset of each field in u_x[]
7918: . u - The field values at this point in space
7919: . u_t - The field time derivative at this point in space (or NULL)
7920: . u_x - The field derivatives at this point in space
7921: . aOff - The offset of each auxiliary field in u[]
7922: . aOff_x - The offset of each auxiliary field in u_x[]
7923: . a - The auxiliary field values at this point in space
7924: . a_t - The auxiliary field time derivative at this point in space (or NULL)
7925: . a_x - The auxiliary field derivatives at this point in space
7926: . t - The current time
7927: . x - The coordinates of this point
7928: . numConstants - The number of constants
7929: . constants - The value of each constant
7930: - f - The value of the function at this point in space
7932: Note:
7933: There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
7934: The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
7935: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7936: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
7938: Level: intermediate
7940: Developer Notes:
7941: This API is specific to only particular usage of `DM`
7943: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7945: .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7946: @*/
7947: PetscErrorCode 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)
7948: {
7952: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
7953: return 0;
7954: }
7956: /*@C
7957: DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.
7959: Not collective
7961: Input Parameters:
7962: + dm - The `DM`
7963: . time - The time
7964: . label - The `DMLabel` marking the portion of the domain to output
7965: . numIds - The number of label ids to use
7966: . ids - The label ids to use for marking
7967: . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7968: . comps - The components to set in the output, or NULL for all components
7969: . U - The input field vector
7970: . funcs - The functions to evaluate, one per field
7971: - mode - The insertion mode for values
7973: Output Parameter:
7974: . X - The output vector
7976: Calling sequence of func:
7977: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7978: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7979: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7980: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
7982: + dim - The spatial dimension
7983: . Nf - The number of input fields
7984: . NfAux - The number of input auxiliary fields
7985: . uOff - The offset of each field in u[]
7986: . uOff_x - The offset of each field in u_x[]
7987: . u - The field values at this point in space
7988: . u_t - The field time derivative at this point in space (or NULL)
7989: . u_x - The field derivatives at this point in space
7990: . aOff - The offset of each auxiliary field in u[]
7991: . aOff_x - The offset of each auxiliary field in u_x[]
7992: . a - The auxiliary field values at this point in space
7993: . a_t - The auxiliary field time derivative at this point in space (or NULL)
7994: . a_x - The auxiliary field derivatives at this point in space
7995: . t - The current time
7996: . x - The coordinates of this point
7997: . numConstants - The number of constants
7998: . constants - The value of each constant
7999: - f - The value of the function at this point in space
8001: Note:
8002: There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8003: 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
8004: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8005: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8007: Level: intermediate
8009: Developer Notes:
8010: This API is specific to only particular usage of `DM`
8012: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8014: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8015: @*/
8016: PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, 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 X)
8017: {
8018: DM dmIn;
8019: Vec localU, localX;
8022: VecGetDM(U, &dmIn);
8023: DMGetLocalVector(dmIn, &localU);
8024: DMGetLocalVector(dm, &localX);
8025: DMGlobalToLocalBegin(dmIn, U, mode, localU);
8026: DMGlobalToLocalEnd(dmIn, U, mode, localU);
8027: DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8028: DMLocalToGlobalBegin(dm, localX, mode, X);
8029: DMLocalToGlobalEnd(dm, localX, mode, X);
8030: DMRestoreLocalVector(dm, &localX);
8031: DMRestoreLocalVector(dmIn, &localU);
8032: return 0;
8033: }
8035: /*@C
8036: 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.
8038: Not collective
8040: Input Parameters:
8041: + dm - The `DM`
8042: . time - The time
8043: . label - The `DMLabel` marking the portion of the domain boundary to output
8044: . numIds - The number of label ids to use
8045: . ids - The label ids to use for marking
8046: . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8047: . comps - The components to set in the output, or NULL for all components
8048: . localU - The input field vector
8049: . funcs - The functions to evaluate, one per field
8050: - mode - The insertion mode for values
8052: Output Parameter:
8053: . localX - The output vector
8055: Calling sequence of func:
8056: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8057: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8058: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8059: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8061: + dim - The spatial dimension
8062: . Nf - The number of input fields
8063: . NfAux - The number of input auxiliary fields
8064: . uOff - The offset of each field in u[]
8065: . uOff_x - The offset of each field in u_x[]
8066: . u - The field values at this point in space
8067: . u_t - The field time derivative at this point in space (or NULL)
8068: . u_x - The field derivatives at this point in space
8069: . aOff - The offset of each auxiliary field in u[]
8070: . aOff_x - The offset of each auxiliary field in u_x[]
8071: . a - The auxiliary field values at this point in space
8072: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8073: . a_x - The auxiliary field derivatives at this point in space
8074: . t - The current time
8075: . x - The coordinates of this point
8076: . n - The face normal
8077: . numConstants - The number of constants
8078: . constants - The value of each constant
8079: - f - The value of the function at this point in space
8081: Note:
8082: There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8083: 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
8084: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8085: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8087: Level: intermediate
8089: Developer Notes:
8090: This API is specific to only particular usage of `DM`
8092: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8094: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8095: @*/
8096: PetscErrorCode 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)
8097: {
8101: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8102: return 0;
8103: }
8105: /*@C
8106: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8108: Collective on dm
8110: Input Parameters:
8111: + dm - The `DM`
8112: . time - The time
8113: . funcs - The functions to evaluate for each field component
8114: . ctxs - Optional array of contexts to pass to each function, or NULL.
8115: - X - The coefficient vector u_h, a global vector
8117: Output Parameter:
8118: . diff - The diff ||u - u_h||_2
8120: Level: developer
8122: Developer Notes:
8123: This API is specific to only particular usage of `DM`
8125: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8127: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8128: @*/
8129: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8130: {
8133: (dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff);
8134: return 0;
8135: }
8137: /*@C
8138: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8140: Collective on dm
8142: Input Parameters:
8143: + dm - The `DM`
8144: , time - The time
8145: . funcs - The gradient functions to evaluate for each field component
8146: . ctxs - Optional array of contexts to pass to each function, or NULL.
8147: . X - The coefficient vector u_h, a global vector
8148: - n - The vector to project along
8150: Output Parameter:
8151: . diff - The diff ||(grad u - grad u_h) . n||_2
8153: Level: developer
8155: Developer Notes:
8156: This API is specific to only particular usage of `DM`
8158: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8160: .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8161: @*/
8162: 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)
8163: {
8166: (dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff);
8167: return 0;
8168: }
8170: /*@C
8171: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8173: Collective on dm
8175: Input Parameters:
8176: + dm - The `DM`
8177: . time - The time
8178: . funcs - The functions to evaluate for each field component
8179: . ctxs - Optional array of contexts to pass to each function, or NULL.
8180: - X - The coefficient vector u_h, a global vector
8182: Output Parameter:
8183: . diff - The array of differences, ||u^f - u^f_h||_2
8185: Level: developer
8187: Developer Notes:
8188: This API is specific to only particular usage of `DM`
8190: The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8192: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8193: @*/
8194: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8195: {
8198: (dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff);
8199: return 0;
8200: }
8202: /*@C
8203: DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8205: Not Collective
8207: Input Parameter:
8208: . dm - The `DM`
8210: Output Parameters:
8211: + nranks - the number of neighbours
8212: - ranks - the neighbors ranks
8214: Note:
8215: Do not free the array, it is freed when the `DM` is destroyed.
8217: Level: beginner
8219: .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8220: @*/
8221: PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8222: {
8224: (dm->ops->getneighbors)(dm, nranks, ranks);
8225: return 0;
8226: }
8228: #include <petsc/private/matimpl.h>
8230: /*
8231: Converts the input vector to a ghosted vector and then calls the standard coloring code.
8232: This has be a different function because it requires DM which is not defined in the Mat library
8233: */
8234: PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8235: {
8236: if (coloring->ctype == IS_COLORING_LOCAL) {
8237: Vec x1local;
8238: DM dm;
8239: MatGetDM(J, &dm);
8241: DMGetLocalVector(dm, &x1local);
8242: DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local);
8243: DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local);
8244: x1 = x1local;
8245: }
8246: MatFDColoringApply_AIJ(J, coloring, x1, sctx);
8247: if (coloring->ctype == IS_COLORING_LOCAL) {
8248: DM dm;
8249: MatGetDM(J, &dm);
8250: DMRestoreLocalVector(dm, &x1);
8251: }
8252: return 0;
8253: }
8255: /*@
8256: MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8258: Input Parameter:
8259: . coloring - the `MatFDColoring` object
8261: Developer Note:
8262: this routine exists because the PETSc `Mat` library does not know about the `DM` objects
8264: Level: advanced
8266: .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8267: @*/
8268: PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8269: {
8270: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8271: return 0;
8272: }
8274: /*@
8275: DMGetCompatibility - determine if two `DM`s are compatible
8277: Collective
8279: Input Parameters:
8280: + dm1 - the first `DM`
8281: - dm2 - the second `DM`
8283: Output Parameters:
8284: + compatible - whether or not the two `DM`s are compatible
8285: - set - whether or not the compatible value was actually determined and set
8287: Notes:
8288: Two `DM`s are deemed compatible if they represent the same parallel decomposition
8289: of the same topology. This implies that the section (field data) on one
8290: "makes sense" with respect to the topology and parallel decomposition of the other.
8291: Loosely speaking, compatible `DM`s represent the same domain and parallel
8292: decomposition, but hold different data.
8294: Typically, one would confirm compatibility if intending to simultaneously iterate
8295: over a pair of vectors obtained from different `DM`s.
8297: For example, two `DMDA` objects are compatible if they have the same local
8298: and global sizes and the same stencil width. They can have different numbers
8299: of degrees of freedom per node. Thus, one could use the node numbering from
8300: either `DM` in bounds for a loop over vectors derived from either `DM`.
8302: Consider the operation of summing data living on a 2-dof `DMDA` to data living
8303: on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8304: .vb
8305: ...
8306: DMGetCompatibility(da1,da2,&compatible,&set);
8307: if (set && compatible) {
8308: DMDAVecGetArrayDOF(da1,vec1,&arr1);
8309: DMDAVecGetArrayDOF(da2,vec2,&arr2);
8310: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8311: for (j=y; j<y+n; ++j) {
8312: for (i=x; i<x+m, ++i) {
8313: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8314: }
8315: }
8316: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8317: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8318: } else {
8319: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8320: }
8321: ...
8322: .ve
8324: Checking compatibility might be expensive for a given implementation of `DM`,
8325: or might be impossible to unambiguously confirm or deny. For this reason,
8326: this function may decline to determine compatibility, and hence users should
8327: always check the "set" output parameter.
8329: A `DM` is always compatible with itself.
8331: In the current implementation, `DM`s which live on "unequal" communicators
8332: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8333: incompatible.
8335: This function is labeled "Collective," as information about all subdomains
8336: is required on each rank. However, in `DM` implementations which store all this
8337: information locally, this function may be merely "Logically Collective".
8339: Developer Note:
8340: Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8341: iff B is compatible with A. Thus, this function checks the implementations
8342: of both dm and dmc (if they are of different types), attempting to determine
8343: compatibility. It is left to `DM` implementers to ensure that symmetry is
8344: preserved. The simplest way to do this is, when implementing type-specific
8345: logic for this function, is to check for existing logic in the implementation
8346: of other `DM` types and let *set = PETSC_FALSE if found.
8348: Level: advanced
8350: .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8351: @*/
8352: PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8353: {
8354: PetscMPIInt compareResult;
8355: DMType type, type2;
8356: PetscBool sameType;
8361: /* Declare a DM compatible with itself */
8362: if (dm1 == dm2) {
8363: *set = PETSC_TRUE;
8364: *compatible = PETSC_TRUE;
8365: return 0;
8366: }
8368: /* Declare a DM incompatible with a DM that lives on an "unequal"
8369: communicator. Note that this does not preclude compatibility with
8370: DMs living on "congruent" or "similar" communicators, but this must be
8371: determined by the implementation-specific logic */
8372: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult);
8373: if (compareResult == MPI_UNEQUAL) {
8374: *set = PETSC_TRUE;
8375: *compatible = PETSC_FALSE;
8376: return 0;
8377: }
8379: /* Pass to the implementation-specific routine, if one exists. */
8380: if (dm1->ops->getcompatibility) {
8381: PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8382: if (*set) return 0;
8383: }
8385: /* If dm1 and dm2 are of different types, then attempt to check compatibility
8386: with an implementation of this function from dm2 */
8387: DMGetType(dm1, &type);
8388: DMGetType(dm2, &type2);
8389: PetscStrcmp(type, type2, &sameType);
8390: if (!sameType && dm2->ops->getcompatibility) {
8391: PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8392: } else {
8393: *set = PETSC_FALSE;
8394: }
8395: return 0;
8396: }
8398: /*@C
8399: DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8401: Logically Collective on dm
8403: Input Parameters:
8404: + DM - the `DM`
8405: . f - the monitor function
8406: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8407: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8409: Options Database Keys:
8410: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8411: does not cancel those set via the options database.
8413: Note:
8414: Several different monitoring routines may be set by calling
8415: `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8416: order in which they were set.
8418: Fortran Note:
8419: Only a single monitor function can be set for each `DM` object
8421: Developer Note:
8422: This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8424: Level: intermediate
8426: .seealso: `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8427: @*/
8428: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8429: {
8430: PetscInt m;
8433: for (m = 0; m < dm->numbermonitors; ++m) {
8434: PetscBool identical;
8436: PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8437: if (identical) return 0;
8438: }
8440: dm->monitor[dm->numbermonitors] = f;
8441: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
8442: dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8443: return 0;
8444: }
8446: /*@
8447: DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8449: Logically Collective on dm
8451: Input Parameter:
8452: . dm - the DM
8454: Options Database Key:
8455: . -dm_monitor_cancel - cancels all monitors that have been hardwired
8456: into a code by calls to `DMonitorSet()`, but does not cancel those
8457: set via the options database
8459: Note:
8460: There is no way to clear one specific monitor from a `DM` object.
8462: Level: intermediate
8464: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8465: @*/
8466: PetscErrorCode DMMonitorCancel(DM dm)
8467: {
8468: PetscInt m;
8471: for (m = 0; m < dm->numbermonitors; ++m) {
8472: if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
8473: }
8474: dm->numbermonitors = 0;
8475: return 0;
8476: }
8478: /*@C
8479: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8481: Collective on dm
8483: Input Parameters:
8484: + dm - `DM` object you wish to monitor
8485: . name - the monitor type one is seeking
8486: . help - message indicating what monitoring is done
8487: . manual - manual page for the monitor
8488: . monitor - the monitor function
8489: - 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
8491: Output Parameter:
8492: . flg - Flag set if the monitor was created
8494: Level: developer
8496: .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8497: `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8498: `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8499: `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8500: `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8501: `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8502: `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8503: @*/
8504: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8505: {
8506: PetscViewer viewer;
8507: PetscViewerFormat format;
8510: PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg);
8511: if (*flg) {
8512: PetscViewerAndFormat *vf;
8514: PetscViewerAndFormatCreate(viewer, format, &vf);
8515: PetscObjectDereference((PetscObject)viewer);
8516: if (monitorsetup) (*monitorsetup)(dm, vf);
8517: DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy);
8518: }
8519: return 0;
8520: }
8522: /*@
8523: DMMonitor - runs the user provided monitor routines, if they exist
8525: Collective on dm
8527: Input Parameters:
8528: . dm - The `DM`
8530: Level: developer
8532: Question:
8533: Note should indicate when during the life of the `DM` the monitor is run. It appears to be related to the discretization process seems rather specialized
8534: since some `DM` have no concept of discretization
8536: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8537: @*/
8538: PetscErrorCode DMMonitor(DM dm)
8539: {
8540: PetscInt m;
8542: if (!dm) return 0;
8544: for (m = 0; m < dm->numbermonitors; ++m) (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8545: return 0;
8546: }
8548: /*@
8549: DMComputeError - Computes the error assuming the user has provided the exact solution functions
8551: Collective on dm
8553: Input Parameters:
8554: + dm - The `DM`
8555: - sol - The solution vector
8557: Input/Output Parameter:
8558: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
8559: contains the error in each field
8561: Output Parameter:
8562: . errorVec - A vector to hold the cellwise error (may be NULL)
8564: Note:
8565: The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
8567: Level: developer
8569: .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8570: @*/
8571: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8572: {
8573: PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8574: void **ctxs;
8575: PetscReal time;
8576: PetscInt Nf, f, Nds, s;
8578: DMGetNumFields(dm, &Nf);
8579: PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
8580: DMGetNumDS(dm, &Nds);
8581: for (s = 0; s < Nds; ++s) {
8582: PetscDS ds;
8583: DMLabel label;
8584: IS fieldIS;
8585: const PetscInt *fields;
8586: PetscInt dsNf;
8588: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
8589: PetscDSGetNumFields(ds, &dsNf);
8590: if (fieldIS) ISGetIndices(fieldIS, &fields);
8591: for (f = 0; f < dsNf; ++f) {
8592: const PetscInt field = fields[f];
8593: PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
8594: }
8595: if (fieldIS) ISRestoreIndices(fieldIS, &fields);
8596: }
8598: DMGetOutputSequenceNumber(dm, NULL, &time);
8599: if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
8600: if (errorVec) {
8601: DM edm;
8602: DMPolytopeType ct;
8603: PetscBool simplex;
8604: PetscInt dim, cStart, Nf;
8606: DMClone(dm, &edm);
8607: DMGetDimension(edm, &dim);
8608: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
8609: DMPlexGetCellType(dm, cStart, &ct);
8610: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8611: DMGetNumFields(dm, &Nf);
8612: for (f = 0; f < Nf; ++f) {
8613: PetscFE fe, efe;
8614: PetscQuadrature q;
8615: const char *name;
8617: DMGetField(dm, f, NULL, (PetscObject *)&fe);
8618: PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
8619: PetscObjectGetName((PetscObject)fe, &name);
8620: PetscObjectSetName((PetscObject)efe, name);
8621: PetscFEGetQuadrature(fe, &q);
8622: PetscFESetQuadrature(efe, q);
8623: DMSetField(edm, f, NULL, (PetscObject)efe);
8624: PetscFEDestroy(&efe);
8625: }
8626: DMCreateDS(edm);
8628: DMCreateGlobalVector(edm, errorVec);
8629: PetscObjectSetName((PetscObject)*errorVec, "Error");
8630: DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
8631: DMDestroy(&edm);
8632: }
8633: PetscFree2(exactSol, ctxs);
8634: return 0;
8635: }
8637: /*@
8638: DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
8640: Not collective
8642: Input Parameter:
8643: . dm - The `DM`
8645: Output Parameter:
8646: . numAux - The number of auxiliary data vectors
8648: Level: advanced
8650: .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8651: @*/
8652: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8653: {
8655: PetscHMapAuxGetSize(dm->auxData, numAux);
8656: return 0;
8657: }
8659: /*@
8660: DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
8662: Not collective
8664: Input Parameters:
8665: + dm - The `DM`
8666: . label - The `DMLabel`
8667: . value - The label value indicating the region
8668: - part - The equation part, or 0 if unused
8670: Output Parameter:
8671: . aux - The `Vec` holding auxiliary field data
8673: Note:
8674: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
8676: Level: advanced
8678: .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8679: @*/
8680: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8681: {
8682: PetscHashAuxKey key, wild = {NULL, 0, 0};
8683: PetscBool has;
8687: key.label = label;
8688: key.value = value;
8689: key.part = part;
8690: PetscHMapAuxHas(dm->auxData, key, &has);
8691: if (has) PetscHMapAuxGet(dm->auxData, key, aux);
8692: else PetscHMapAuxGet(dm->auxData, wild, aux);
8693: return 0;
8694: }
8696: /*@
8697: DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
8699: Not collective because auxiliary vectors are not parallel
8701: Input Parameters:
8702: + dm - The `DM`
8703: . label - The `DMLabel`
8704: . value - The label value indicating the region
8705: . part - The equation part, or 0 if unused
8706: - aux - The `Vec` holding auxiliary field data
8708: Level: advanced
8710: .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8711: @*/
8712: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8713: {
8714: Vec old;
8715: PetscHashAuxKey key;
8719: key.label = label;
8720: key.value = value;
8721: key.part = part;
8722: PetscHMapAuxGet(dm->auxData, key, &old);
8723: PetscObjectReference((PetscObject)aux);
8724: PetscObjectDereference((PetscObject)old);
8725: if (!aux) PetscHMapAuxDel(dm->auxData, key);
8726: else PetscHMapAuxSet(dm->auxData, key, aux);
8727: return 0;
8728: }
8730: /*@C
8731: DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
8733: Not collective
8735: Input Parameter:
8736: . dm - The `DM`
8738: Output Parameters:
8739: + labels - The `DMLabel`s for each `Vec`
8740: . values - The label values for each `Vec`
8741: - parts - The equation parts for each `Vec`
8743: Note:
8744: The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
8746: Level: advanced
8748: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
8749: @*/
8750: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
8751: {
8752: PetscHashAuxKey *keys;
8753: PetscInt n, i, off = 0;
8759: DMGetNumAuxiliaryVec(dm, &n);
8760: PetscMalloc1(n, &keys);
8761: PetscHMapAuxGetKeys(dm->auxData, &off, keys);
8762: for (i = 0; i < n; ++i) {
8763: labels[i] = keys[i].label;
8764: values[i] = keys[i].value;
8765: parts[i] = keys[i].part;
8766: }
8767: PetscFree(keys);
8768: return 0;
8769: }
8771: /*@
8772: DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
8774: Not collective
8776: Input Parameter:
8777: . dm - The `DM`
8779: Output Parameter:
8780: . dmNew - The new `DM`, now with the same auxiliary data
8782: Level: advanced
8784: Note:
8785: This is a shallow copy of the auxiliary vectors
8787: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8788: @*/
8789: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
8790: {
8792: PetscHMapAuxDestroy(&dmNew->auxData);
8793: PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
8794: return 0;
8795: }
8797: /*@C
8798: DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
8800: Not collective
8802: Input Parameters:
8803: + ct - The `DMPolytopeType`
8804: . sourceCone - The source arrangement of faces
8805: - targetCone - The target arrangement of faces
8807: Output Parameters:
8808: + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
8809: - found - Flag indicating that a suitable orientation was found
8811: Level: advanced
8813: Note:
8814: An arrangement is a face order combined with an orientation for each face
8816: Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8817: that labels each arrangement (face ordering plus orientation for each face).
8819: See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
8821: .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
8822: @*/
8823: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
8824: {
8825: const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
8826: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8827: PetscInt o, c;
8829: if (!nO) {
8830: *ornt = 0;
8831: *found = PETSC_TRUE;
8832: return 0;
8833: }
8834: for (o = -nO; o < nO; ++o) {
8835: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
8837: for (c = 0; c < cS; ++c)
8838: if (sourceCone[arr[c * 2]] != targetCone[c]) break;
8839: if (c == cS) {
8840: *ornt = o;
8841: break;
8842: }
8843: }
8844: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8845: return 0;
8846: }
8848: /*@C
8849: DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
8851: Not collective
8853: Input Parameters:
8854: + ct - The `DMPolytopeType`
8855: . sourceCone - The source arrangement of faces
8856: - targetCone - The target arrangement of faces
8858: Output Parameters:
8859: . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
8861: Level: advanced
8863: Note:
8864: This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
8866: Developer Note:
8867: It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
8869: .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
8870: @*/
8871: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8872: {
8873: PetscBool found;
8875: DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
8877: return 0;
8878: }
8880: /*@C
8881: DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
8883: Not collective
8885: Input Parameters:
8886: + ct - The `DMPolytopeType`
8887: . sourceVert - The source arrangement of vertices
8888: - targetVert - The target arrangement of vertices
8890: Output Parameters:
8891: + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
8892: - found - Flag indicating that a suitable orientation was found
8894: Level: advanced
8896: Note:
8897: An arrangement is a vertex order
8899: Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8900: that labels each arrangement (vertex ordering).
8902: See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
8904: .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
8905: @*/
8906: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
8907: {
8908: const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
8909: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8910: PetscInt o, c;
8912: if (!nO) {
8913: *ornt = 0;
8914: *found = PETSC_TRUE;
8915: return 0;
8916: }
8917: for (o = -nO; o < nO; ++o) {
8918: const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
8920: for (c = 0; c < cS; ++c)
8921: if (sourceVert[arr[c]] != targetVert[c]) break;
8922: if (c == cS) {
8923: *ornt = o;
8924: break;
8925: }
8926: }
8927: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8928: return 0;
8929: }
8931: /*@C
8932: DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
8934: Not collective
8936: Input Parameters:
8937: + ct - The `DMPolytopeType`
8938: . sourceCone - The source arrangement of vertices
8939: - targetCone - The target arrangement of vertices
8941: Output Parameters:
8942: . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
8944: Level: advanced
8946: Note:
8947: This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
8949: Developer Note:
8950: It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
8952: .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
8953: @*/
8954: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8955: {
8956: PetscBool found;
8958: DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
8960: return 0;
8961: }
8963: /*@C
8964: DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
8966: Not collective
8968: Input Parameters:
8969: + ct - The `DMPolytopeType`
8970: - point - Coordinates of the point
8972: Output Parameters:
8973: . inside - Flag indicating whether the point is inside the reference cell of given type
8975: Level: advanced
8977: .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
8978: @*/
8979: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
8980: {
8981: PetscReal sum = 0.0;
8982: PetscInt d;
8984: *inside = PETSC_TRUE;
8985: switch (ct) {
8986: case DM_POLYTOPE_TRIANGLE:
8987: case DM_POLYTOPE_TETRAHEDRON:
8988: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
8989: if (point[d] < -1.0) {
8990: *inside = PETSC_FALSE;
8991: break;
8992: }
8993: sum += point[d];
8994: }
8995: if (sum > PETSC_SMALL) {
8996: *inside = PETSC_FALSE;
8997: break;
8998: }
8999: break;
9000: case DM_POLYTOPE_QUADRILATERAL:
9001: case DM_POLYTOPE_HEXAHEDRON:
9002: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9003: if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9004: *inside = PETSC_FALSE;
9005: break;
9006: }
9007: break;
9008: default:
9009: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9010: }
9011: return 0;
9012: }