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_VALGRIND)
15: # include <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_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", "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
25: const char *const DMCopyLabelsModes[] = {"replace","keep","fail","DMCopyLabelsMode","DM_COPY_LABELS_", NULL};
27: /*@
28: DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
30: If you never call DMSetType() it will generate an
31: error when you try to use the vector.
33: Collective
35: Input Parameter:
36: . comm - The communicator for the DM object
38: Output Parameter:
39: . dm - The DM object
41: Level: beginner
43: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
44: @*/
45: PetscErrorCode DMCreate(MPI_Comm comm,DM *dm)
46: {
47: DM v;
48: PetscDS ds;
51: *dm = NULL;
52: DMInitializePackage();
54: PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);
56: v->setupcalled = PETSC_FALSE;
57: v->setfromoptionscalled = PETSC_FALSE;
58: v->ltogmap = NULL;
59: v->bind_below = 0;
60: v->bs = 1;
61: v->coloringtype = IS_COLORING_GLOBAL;
62: PetscSFCreate(comm, &v->sf);
63: PetscSFCreate(comm, &v->sectionSF);
64: v->labels = NULL;
65: v->adjacency[0] = PETSC_FALSE;
66: v->adjacency[1] = PETSC_TRUE;
67: v->depthLabel = NULL;
68: v->celltypeLabel = NULL;
69: v->localSection = NULL;
70: v->globalSection = NULL;
71: v->defaultConstraint.section = NULL;
72: v->defaultConstraint.mat = NULL;
73: v->defaultConstraint.bias = NULL;
74: v->L = NULL;
75: v->maxCell = NULL;
76: v->bdtype = NULL;
77: v->dimEmbed = PETSC_DEFAULT;
78: v->dim = PETSC_DETERMINE;
79: {
80: PetscInt i;
81: for (i = 0; i < 10; ++i) {
82: v->nullspaceConstructors[i] = NULL;
83: v->nearnullspaceConstructors[i] = NULL;
84: }
85: }
86: PetscDSCreate(PETSC_COMM_SELF, &ds);
87: DMSetRegionDS(v, NULL, NULL, ds);
88: PetscDSDestroy(&ds);
89: PetscHMapAuxCreate(&v->auxData);
90: v->dmBC = NULL;
91: v->coarseMesh = NULL;
92: v->outputSequenceNum = -1;
93: v->outputSequenceVal = 0.0;
94: DMSetVecType(v,VECSTANDARD);
95: DMSetMatType(v,MATAIJ);
97: *dm = v;
98: return 0;
99: }
101: /*@
102: DMClone - Creates a DM object with the same topology as the original.
104: Collective
106: Input Parameter:
107: . dm - The original DM object
109: Output Parameter:
110: . newdm - The new DM object
112: Level: beginner
114: Notes:
115: For some DM implementations this is a shallow clone, the result of which may share (referent counted) information with its parent. For example,
116: DMClone() applied to a DMPLEX object will result in a new DMPLEX that shares the topology with the original DMPLEX. It does not
117: share the PetscSection of the original DM.
119: The clone is considered set up iff the original is.
121: .seealso: DMDestroy(), DMCreate(), DMSetType(), DMSetLocalSection(), DMSetGlobalSection()
123: @*/
124: PetscErrorCode DMClone(DM dm, DM *newdm)
125: {
126: PetscSF sf;
127: Vec coords;
128: void *ctx;
129: PetscInt dim, cdim;
133: DMCreate(PetscObjectComm((PetscObject) dm), newdm);
134: DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL);
135: (*newdm)->leveldown = dm->leveldown;
136: (*newdm)->levelup = dm->levelup;
137: (*newdm)->prealloc_only = dm->prealloc_only;
138: PetscFree((*newdm)->vectype);
139: PetscStrallocpy(dm->vectype,(char**)&(*newdm)->vectype);
140: PetscFree((*newdm)->mattype);
141: PetscStrallocpy(dm->mattype,(char**)&(*newdm)->mattype);
142: DMGetDimension(dm, &dim);
143: DMSetDimension(*newdm, dim);
144: if (dm->ops->clone) {
145: (*dm->ops->clone)(dm, newdm);
146: }
147: (*newdm)->setupcalled = dm->setupcalled;
148: DMGetPointSF(dm, &sf);
149: DMSetPointSF(*newdm, sf);
150: DMGetApplicationContext(dm, &ctx);
151: DMSetApplicationContext(*newdm, ctx);
152: if (dm->coordinateDM) {
153: DM ncdm;
154: PetscSection cs;
155: PetscInt pEnd = -1, pEndMax = -1;
157: DMGetLocalSection(dm->coordinateDM, &cs);
158: if (cs) PetscSectionGetChart(cs, NULL, &pEnd);
159: MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
160: if (pEndMax >= 0) {
161: DMClone(dm->coordinateDM, &ncdm);
162: DMCopyDisc(dm->coordinateDM, ncdm);
163: DMSetLocalSection(ncdm, cs);
164: DMSetCoordinateDM(*newdm, ncdm);
165: DMDestroy(&ncdm);
166: }
167: }
168: DMGetCoordinateDim(dm, &cdim);
169: DMSetCoordinateDim(*newdm, cdim);
170: DMGetCoordinatesLocal(dm, &coords);
171: if (coords) {
172: DMSetCoordinatesLocal(*newdm, coords);
173: } else {
174: DMGetCoordinates(dm, &coords);
175: if (coords) DMSetCoordinates(*newdm, coords);
176: }
177: {
178: PetscBool isper;
179: const PetscReal *maxCell, *L;
180: const DMBoundaryType *bd;
181: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
182: DMSetPeriodicity(*newdm, isper, maxCell, L, bd);
183: }
184: {
185: PetscBool useCone, useClosure;
187: DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
188: DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
189: }
190: return 0;
191: }
193: /*@C
194: DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
196: Logically Collective on da
198: Input Parameters:
199: + da - initial distributed array
200: - ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL
202: Options Database:
203: . -dm_vec_type ctype - the type of vector to create
205: Level: intermediate
207: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
208: @*/
209: PetscErrorCode DMSetVecType(DM da,VecType ctype)
210: {
212: PetscFree(da->vectype);
213: PetscStrallocpy(ctype,(char**)&da->vectype);
214: return 0;
215: }
217: /*@C
218: DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
220: Logically Collective on da
222: Input Parameter:
223: . da - initial distributed array
225: Output Parameter:
226: . ctype - the vector type
228: Level: intermediate
230: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
231: @*/
232: PetscErrorCode DMGetVecType(DM da,VecType *ctype)
233: {
235: *ctype = da->vectype;
236: return 0;
237: }
239: /*@
240: VecGetDM - Gets the DM defining the data layout of the vector
242: Not collective
244: Input Parameter:
245: . v - The Vec
247: Output Parameter:
248: . dm - The DM
250: Level: intermediate
252: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
253: @*/
254: PetscErrorCode VecGetDM(Vec v, DM *dm)
255: {
258: PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
259: return 0;
260: }
262: /*@
263: VecSetDM - Sets the DM defining the data layout of the vector.
265: Not collective
267: Input Parameters:
268: + v - The Vec
269: - dm - The DM
271: Note: This is NOT the same as DMCreateGlobalVector() since it does not change the view methods or perform other customization, but merely sets the DM member.
273: Level: intermediate
275: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
276: @*/
277: PetscErrorCode VecSetDM(Vec v, DM dm)
278: {
281: PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
282: return 0;
283: }
285: /*@C
286: DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM
288: Logically Collective on dm
290: Input Parameters:
291: + dm - the DM context
292: - ctype - the matrix type
294: Options Database:
295: . -dm_is_coloring_type - global or local
297: Level: intermediate
299: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
300: DMGetISColoringType()
301: @*/
302: PetscErrorCode DMSetISColoringType(DM dm,ISColoringType ctype)
303: {
305: dm->coloringtype = ctype;
306: return 0;
307: }
309: /*@C
310: DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM
312: Logically Collective on dm
314: Input Parameter:
315: . dm - the DM context
317: Output Parameter:
318: . ctype - the matrix type
320: Options Database:
321: . -dm_is_coloring_type - global or local
323: Level: intermediate
325: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
326: DMGetISColoringType()
327: @*/
328: PetscErrorCode DMGetISColoringType(DM dm,ISColoringType *ctype)
329: {
331: *ctype = dm->coloringtype;
332: return 0;
333: }
335: /*@C
336: DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
338: Logically Collective on dm
340: Input Parameters:
341: + dm - the DM context
342: - ctype - the matrix type
344: Options Database:
345: . -dm_mat_type ctype - the type of the matrix to create
347: Level: intermediate
349: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
350: @*/
351: PetscErrorCode DMSetMatType(DM dm,MatType ctype)
352: {
354: PetscFree(dm->mattype);
355: PetscStrallocpy(ctype,(char**)&dm->mattype);
356: return 0;
357: }
359: /*@C
360: DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
362: Logically Collective on dm
364: Input Parameter:
365: . dm - the DM context
367: Output Parameter:
368: . ctype - the matrix type
370: Options Database:
371: . -dm_mat_type ctype - the matrix type
373: Level: intermediate
375: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
376: @*/
377: PetscErrorCode DMGetMatType(DM dm,MatType *ctype)
378: {
380: *ctype = dm->mattype;
381: return 0;
382: }
384: /*@
385: MatGetDM - Gets the DM defining the data layout of the matrix
387: Not collective
389: Input Parameter:
390: . A - The Mat
392: Output Parameter:
393: . dm - The DM
395: Level: intermediate
397: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
398: the Mat through a PetscObjectCompose() operation
400: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
401: @*/
402: PetscErrorCode MatGetDM(Mat A, DM *dm)
403: {
406: PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
407: return 0;
408: }
410: /*@
411: MatSetDM - Sets the DM defining the data layout of the matrix
413: Not collective
415: Input Parameters:
416: + A - The Mat
417: - dm - The DM
419: Level: intermediate
421: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
422: the Mat through a PetscObjectCompose() operation
424: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
425: @*/
426: PetscErrorCode MatSetDM(Mat A, DM dm)
427: {
430: PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
431: return 0;
432: }
434: /*@C
435: DMSetOptionsPrefix - Sets the prefix used for searching for all
436: DM options in the database.
438: Logically Collective on dm
440: Input Parameters:
441: + da - the DM context
442: - prefix - the prefix to prepend to all option names
444: Notes:
445: A hyphen (-) must NOT be given at the beginning of the prefix name.
446: The first character of all runtime options is AUTOMATICALLY the hyphen.
448: Level: advanced
450: .seealso: DMSetFromOptions()
451: @*/
452: PetscErrorCode DMSetOptionsPrefix(DM dm,const char prefix[])
453: {
455: PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
456: if (dm->sf) {
457: PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
458: }
459: if (dm->sectionSF) {
460: PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
461: }
462: return 0;
463: }
465: /*@C
466: DMAppendOptionsPrefix - Appends to the prefix used for searching for all
467: DM options in the database.
469: Logically Collective on dm
471: Input Parameters:
472: + dm - the DM context
473: - prefix - the prefix string to prepend to all DM option requests
475: Notes:
476: A hyphen (-) must NOT be given at the beginning of the prefix name.
477: The first character of all runtime options is AUTOMATICALLY the hyphen.
479: Level: advanced
481: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
482: @*/
483: PetscErrorCode DMAppendOptionsPrefix(DM dm,const char prefix[])
484: {
486: PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
487: return 0;
488: }
490: /*@C
491: DMGetOptionsPrefix - Gets the prefix used for searching for all
492: DM options in the database.
494: Not Collective
496: Input Parameters:
497: . dm - the DM context
499: Output Parameters:
500: . prefix - pointer to the prefix string used is returned
502: Notes:
503: On the fortran side, the user should pass in a string 'prefix' of
504: sufficient length to hold the prefix.
506: Level: advanced
508: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
509: @*/
510: PetscErrorCode DMGetOptionsPrefix(DM dm,const char *prefix[])
511: {
513: PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
514: return 0;
515: }
517: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
518: {
519: PetscInt refct = ((PetscObject) dm)->refct;
521: *ncrefct = 0;
522: if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
523: refct--;
524: if (recurseCoarse) {
525: PetscInt coarseCount;
527: DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
528: refct += coarseCount;
529: }
530: }
531: if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
532: refct--;
533: if (recurseFine) {
534: PetscInt fineCount;
536: DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
537: refct += fineCount;
538: }
539: }
540: *ncrefct = refct;
541: return 0;
542: }
544: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
545: {
546: DMLabelLink next = dm->labels;
548: /* destroy the labels */
549: while (next) {
550: DMLabelLink tmp = next->next;
552: if (next->label == dm->depthLabel) dm->depthLabel = NULL;
553: if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
554: DMLabelDestroy(&next->label);
555: PetscFree(next);
556: next = tmp;
557: }
558: dm->labels = NULL;
559: return 0;
560: }
562: /*@C
563: DMDestroy - Destroys a vector packer or DM.
565: Collective on dm
567: Input Parameter:
568: . dm - the DM object to destroy
570: Level: developer
572: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
574: @*/
575: PetscErrorCode DMDestroy(DM *dm)
576: {
577: PetscInt cnt;
578: DMNamedVecLink nlink,nnext;
580: if (!*dm) return 0;
583: /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
584: DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
585: --((PetscObject)(*dm))->refct;
586: if (--cnt > 0) {*dm = NULL; return 0;}
587: if (((PetscObject)(*dm))->refct < 0) return 0;
588: ((PetscObject)(*dm))->refct = 0;
590: DMClearGlobalVectors(*dm);
591: DMClearLocalVectors(*dm);
593: nnext=(*dm)->namedglobal;
594: (*dm)->namedglobal = NULL;
595: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
596: nnext = nlink->next;
598: PetscFree(nlink->name);
599: VecDestroy(&nlink->X);
600: PetscFree(nlink);
601: }
602: nnext=(*dm)->namedlocal;
603: (*dm)->namedlocal = NULL;
604: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
605: nnext = nlink->next;
607: PetscFree(nlink->name);
608: VecDestroy(&nlink->X);
609: PetscFree(nlink);
610: }
612: /* Destroy the list of hooks */
613: {
614: DMCoarsenHookLink link,next;
615: for (link=(*dm)->coarsenhook; link; link=next) {
616: next = link->next;
617: PetscFree(link);
618: }
619: (*dm)->coarsenhook = NULL;
620: }
621: {
622: DMRefineHookLink link,next;
623: for (link=(*dm)->refinehook; link; link=next) {
624: next = link->next;
625: PetscFree(link);
626: }
627: (*dm)->refinehook = NULL;
628: }
629: {
630: DMSubDomainHookLink link,next;
631: for (link=(*dm)->subdomainhook; link; link=next) {
632: next = link->next;
633: PetscFree(link);
634: }
635: (*dm)->subdomainhook = NULL;
636: }
637: {
638: DMGlobalToLocalHookLink link,next;
639: for (link=(*dm)->gtolhook; link; link=next) {
640: next = link->next;
641: PetscFree(link);
642: }
643: (*dm)->gtolhook = NULL;
644: }
645: {
646: DMLocalToGlobalHookLink link,next;
647: for (link=(*dm)->ltoghook; link; link=next) {
648: next = link->next;
649: PetscFree(link);
650: }
651: (*dm)->ltoghook = NULL;
652: }
653: /* Destroy the work arrays */
654: {
655: DMWorkLink link,next;
657: for (link=(*dm)->workin; link; link=next) {
658: next = link->next;
659: PetscFree(link->mem);
660: PetscFree(link);
661: }
662: (*dm)->workin = NULL;
663: }
664: /* destroy the labels */
665: DMDestroyLabelLinkList_Internal(*dm);
666: /* destroy the fields */
667: DMClearFields(*dm);
668: /* destroy the boundaries */
669: {
670: DMBoundary next = (*dm)->boundary;
671: while (next) {
672: DMBoundary b = next;
674: next = b->next;
675: PetscFree(b);
676: }
677: }
679: PetscObjectDestroy(&(*dm)->dmksp);
680: PetscObjectDestroy(&(*dm)->dmsnes);
681: PetscObjectDestroy(&(*dm)->dmts);
683: if ((*dm)->ctx && (*dm)->ctxdestroy) {
684: (*(*dm)->ctxdestroy)(&(*dm)->ctx);
685: }
686: MatFDColoringDestroy(&(*dm)->fd);
687: ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
688: PetscFree((*dm)->vectype);
689: PetscFree((*dm)->mattype);
691: PetscSectionDestroy(&(*dm)->localSection);
692: PetscSectionDestroy(&(*dm)->globalSection);
693: PetscLayoutDestroy(&(*dm)->map);
694: PetscSectionDestroy(&(*dm)->defaultConstraint.section);
695: MatDestroy(&(*dm)->defaultConstraint.mat);
696: PetscSFDestroy(&(*dm)->sf);
697: PetscSFDestroy(&(*dm)->sectionSF);
698: if ((*dm)->useNatural) {
699: if ((*dm)->sfNatural) {
700: PetscSFDestroy(&(*dm)->sfNatural);
701: }
702: PetscObjectDereference((PetscObject) (*dm)->sfMigration);
703: }
704: {
705: Vec *auxData;
706: PetscInt n, i, off = 0;
708: PetscHMapAuxGetSize((*dm)->auxData, &n);
709: PetscMalloc1(n, &auxData);
710: PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
711: for (i = 0; i < n; ++i) VecDestroy(&auxData[i]);
712: PetscFree(auxData);
713: PetscHMapAuxDestroy(&(*dm)->auxData);
714: }
715: if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
716: DMSetFineDM((*dm)->coarseMesh,NULL);
717: }
719: DMDestroy(&(*dm)->coarseMesh);
720: if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
721: DMSetCoarseDM((*dm)->fineMesh,NULL);
722: }
723: DMDestroy(&(*dm)->fineMesh);
724: DMFieldDestroy(&(*dm)->coordinateField);
725: DMDestroy(&(*dm)->coordinateDM);
726: VecDestroy(&(*dm)->coordinates);
727: VecDestroy(&(*dm)->coordinatesLocal);
728: PetscFree((*dm)->L);
729: PetscFree((*dm)->maxCell);
730: PetscFree((*dm)->bdtype);
731: if ((*dm)->transformDestroy) (*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);
732: DMDestroy(&(*dm)->transformDM);
733: VecDestroy(&(*dm)->transform);
735: DMClearDS(*dm);
736: DMDestroy(&(*dm)->dmBC);
737: /* if memory was published with SAWs then destroy it */
738: PetscObjectSAWsViewOff((PetscObject)*dm);
740: if ((*dm)->ops->destroy) {
741: (*(*dm)->ops->destroy)(*dm);
742: }
743: DMMonitorCancel(*dm);
744: #ifdef PETSC_HAVE_LIBCEED
745: CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
746: CeedDestroy(&(*dm)->ceed);
747: #endif
748: /* We do not destroy (*dm)->data here so that we can reference count backend objects */
749: PetscHeaderDestroy(dm);
750: return 0;
751: }
753: /*@
754: DMSetUp - sets up the data structures inside a DM object
756: Collective on dm
758: Input Parameter:
759: . dm - the DM object to setup
761: Level: developer
763: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
765: @*/
766: PetscErrorCode DMSetUp(DM dm)
767: {
769: if (dm->setupcalled) return 0;
770: if (dm->ops->setup) {
771: (*dm->ops->setup)(dm);
772: }
773: dm->setupcalled = PETSC_TRUE;
774: return 0;
775: }
777: /*@
778: DMSetFromOptions - sets parameters in a DM from the options database
780: Collective on dm
782: Input Parameter:
783: . dm - the DM object to set options for
785: Options Database:
786: + -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
787: . -dm_vec_type <type> - type of vector to create inside DM
788: . -dm_mat_type <type> - type of matrix to create inside DM
789: . -dm_is_coloring_type - <global or local>
790: - -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
792: DMPLEX Specific creation options
793: + -dm_plex_filename <str> - File containing a mesh
794: . -dm_plex_boundary_filename <str> - File containing a mesh boundary
795: . -dm_plex_name <str> - Name of the mesh in the file
796: . -dm_plex_shape <shape> - The domain shape, such as DM_SHAPE_BOX, DM_SHAPE_SPHERE, etc.
797: . -dm_plex_cell <ct> - Cell shape
798: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
799: . -dm_plex_dim <dim> - Set the topological dimension
800: . -dm_plex_simplex <bool> - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
801: . -dm_plex_interpolate <bool> - PETSC_TRUE turns on topological interpolation (creating edges and faces)
802: . -dm_plex_scale <sc> - Scale factor for mesh coordinates
803: . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension
804: . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box
805: . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box
806: . -dm_plex_box_bd <bx,by,bz> - Specify the DMBoundaryType for each direction
807: . -dm_plex_sphere_radius <r> - The sphere radius
808: . -dm_plex_ball_radius <r> - Radius of the ball
809: . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction
810: . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder
811: . -dm_plex_reorder <order> - Reorder the mesh using the specified algorithm
812: . -dm_refine_pre <n> - The number of refinements before distribution
813: . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution
814: . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution
815: . -dm_refine <n> - The number of refinements after distribution
816: . -dm_extrude <l> - Activate extrusion and specify the number of layers to extrude
817: . -dm_plex_transform_extrude_thickness <t> - The total thickness of extruded layers
818: . -dm_plex_transform_extrude_use_tensor <bool> - Use tensor cells when extruding
819: . -dm_plex_transform_extrude_symmetric <bool> - Extrude layers symmetrically about the surface
820: . -dm_plex_transform_extrude_normal <n0,...,nd> - Specify the extrusion direction
821: . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
822: . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary
823: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
824: . -dm_distribute <bool> - Flag to redistribute a mesh among processes
825: . -dm_distribute_overlap <n> - The size of the overlap halo
826: . -dm_plex_adj_cone <bool> - Set adjacency direction
827: - -dm_plex_adj_closure <bool> - Set adjacency size
829: DMPLEX Specific Checks
830: + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
831: . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
832: . -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()
833: . -dm_plex_check_geometry - Check that cells have positive volume - DMPlexCheckGeometry()
834: . -dm_plex_check_pointsf - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
835: . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
836: - -dm_plex_check_all - Perform all the checks above
838: Level: intermediate
840: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(),
841: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces(), DMPlexCheckGeometry(), DMPlexCheckPointSF(), DMPlexCheckInterfaceCones()
843: @*/
844: PetscErrorCode DMSetFromOptions(DM dm)
845: {
846: char typeName[256];
847: PetscBool flg;
851: dm->setfromoptionscalled = PETSC_TRUE;
852: if (dm->sf) PetscSFSetFromOptions(dm->sf);
853: if (dm->sectionSF) PetscSFSetFromOptions(dm->sectionSF);
854: PetscObjectOptionsBegin((PetscObject)dm);
855: PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
856: PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
857: if (flg) {
858: DMSetVecType(dm,typeName);
859: }
860: PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
861: if (flg) {
862: DMSetMatType(dm,typeName);
863: }
864: PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
865: 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);
866: if (dm->ops->setfromoptions) {
867: (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
868: }
869: /* process any options handlers added with PetscObjectAddOptionsHandler() */
870: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
871: PetscOptionsEnd();
872: return 0;
873: }
875: /*@C
876: DMViewFromOptions - View from Options
878: Collective on DM
880: Input Parameters:
881: + dm - the DM object
882: . obj - Optional object
883: - name - command line option
885: Level: intermediate
886: .seealso: DM, DMView, PetscObjectViewFromOptions(), DMCreate()
887: @*/
888: PetscErrorCode DMViewFromOptions(DM dm,PetscObject obj,const char name[])
889: {
891: PetscObjectViewFromOptions((PetscObject)dm,obj,name);
892: return 0;
893: }
895: /*@C
896: DMView - Views a DM
898: Collective on dm
900: Input Parameters:
901: + dm - the DM object to view
902: - v - the viewer
904: Notes:
905: Using PETSCVIEWERHDF5 type with PETSC_VIEWER_HDF5_PETSC format, one can save multiple DMPlex
906: meshes in a single HDF5 file. This in turn requires one to name the DMPlex object with PetscObjectSetName()
907: before saving it with DMView() and before loading it with DMLoad() for identification of the mesh object.
909: Level: beginner
911: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMLoad(), PetscObjectSetName()
913: @*/
914: PetscErrorCode DMView(DM dm,PetscViewer v)
915: {
916: PetscBool isbinary;
917: PetscMPIInt size;
918: PetscViewerFormat format;
921: if (!v) {
922: PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
923: }
925: /* Ideally, we would like to have this test on.
926: However, it currently breaks socket viz via GLVis.
927: During DMView(parallel_mesh,glvis_viewer), each
928: process opens a sequential ASCII socket to visualize
929: the local mesh, and PetscObjectView(dm,local_socket)
930: is internally called inside VecView_GLVis, incurring
931: in an error here */
933: PetscViewerCheckWritable(v);
935: PetscViewerGetFormat(v,&format);
936: MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
937: if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return 0;
938: PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
939: PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
940: if (isbinary) {
941: PetscInt classid = DM_FILE_CLASSID;
942: char type[256];
944: PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
945: PetscStrncpy(type,((PetscObject)dm)->type_name,256);
946: PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
947: }
948: if (dm->ops->view) {
949: (*dm->ops->view)(dm,v);
950: }
951: return 0;
952: }
954: /*@
955: DMCreateGlobalVector - Creates a global vector from a DM object
957: Collective on dm
959: Input Parameter:
960: . dm - the DM object
962: Output Parameter:
963: . vec - the global vector
965: Level: beginner
967: .seealso DMCreateLocalVector(), DMGetGlobalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
969: @*/
970: PetscErrorCode DMCreateGlobalVector(DM dm,Vec *vec)
971: {
975: (*dm->ops->createglobalvector)(dm,vec);
976: if (PetscDefined(USE_DEBUG)) {
977: DM vdm;
979: VecGetDM(*vec,&vdm);
981: }
982: return 0;
983: }
985: /*@
986: DMCreateLocalVector - Creates a local vector from a DM object
988: Not Collective
990: Input Parameter:
991: . dm - the DM object
993: Output Parameter:
994: . vec - the local vector
996: Level: beginner
998: .seealso DMCreateGlobalVector(), DMGetLocalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1000: @*/
1001: PetscErrorCode DMCreateLocalVector(DM dm,Vec *vec)
1002: {
1006: (*dm->ops->createlocalvector)(dm,vec);
1007: if (PetscDefined(USE_DEBUG)) {
1008: DM vdm;
1010: VecGetDM(*vec,&vdm);
1012: }
1013: return 0;
1014: }
1016: /*@
1017: DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
1019: Collective on dm
1021: Input Parameter:
1022: . dm - the DM that provides the mapping
1024: Output Parameter:
1025: . ltog - the mapping
1027: Level: intermediate
1029: Notes:
1030: This mapping can then be used by VecSetLocalToGlobalMapping() or
1031: MatSetLocalToGlobalMapping().
1033: .seealso: DMCreateLocalVector()
1034: @*/
1035: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1036: {
1037: PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1041: if (!dm->ltogmap) {
1042: PetscSection section, sectionGlobal;
1044: DMGetLocalSection(dm, §ion);
1045: if (section) {
1046: const PetscInt *cdofs;
1047: PetscInt *ltog;
1048: PetscInt pStart, pEnd, n, p, k, l;
1050: DMGetGlobalSection(dm, §ionGlobal);
1051: PetscSectionGetChart(section, &pStart, &pEnd);
1052: PetscSectionGetStorageSize(section, &n);
1053: PetscMalloc1(n, <og); /* We want the local+overlap size */
1054: for (p = pStart, l = 0; p < pEnd; ++p) {
1055: PetscInt bdof, cdof, dof, off, c, cind;
1057: /* Should probably use constrained dofs */
1058: PetscSectionGetDof(section, p, &dof);
1059: PetscSectionGetConstraintDof(section, p, &cdof);
1060: PetscSectionGetConstraintIndices(section, p, &cdofs);
1061: PetscSectionGetOffset(sectionGlobal, p, &off);
1062: /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1063: bdof = cdof && (dof-cdof) ? 1 : dof;
1064: if (dof) {
1065: bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1066: }
1068: for (c = 0, cind = 0; c < dof; ++c, ++l) {
1069: if (cind < cdof && c == cdofs[cind]) {
1070: ltog[l] = off < 0 ? off-c : -(off+c+1);
1071: cind++;
1072: } else {
1073: ltog[l] = (off < 0 ? -(off+1) : off) + c - cind;
1074: }
1075: }
1076: }
1077: /* Must have same blocksize on all procs (some might have no points) */
1078: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1079: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1080: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1081: else {bs = bsMinMax[0];}
1082: bs = bs < 0 ? 1 : bs;
1083: /* Must reduce indices by blocksize */
1084: if (bs > 1) {
1085: for (l = 0, k = 0; l < n; l += bs, ++k) {
1086: // Integer division of negative values truncates toward zero(!), not toward negative infinity
1087: ltog[k] = ltog[l] >= 0 ? ltog[l]/bs : -(-(ltog[l]+1)/bs + 1);
1088: }
1089: n /= bs;
1090: }
1091: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1092: PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1093: } else {
1095: (*dm->ops->getlocaltoglobalmapping)(dm);
1096: }
1097: }
1098: *ltog = dm->ltogmap;
1099: return 0;
1100: }
1102: /*@
1103: DMGetBlockSize - Gets the inherent block size associated with a DM
1105: Not Collective
1107: Input Parameter:
1108: . dm - the DM with block structure
1110: Output Parameter:
1111: . bs - the block size, 1 implies no exploitable block structure
1113: Level: intermediate
1115: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1116: @*/
1117: PetscErrorCode DMGetBlockSize(DM dm,PetscInt *bs)
1118: {
1122: *bs = dm->bs;
1123: return 0;
1124: }
1126: /*@C
1127: DMCreateInterpolation - Gets interpolation matrix between two DM objects
1129: Collective on dmc
1131: Input Parameters:
1132: + dmc - the DM object
1133: - dmf - the second, finer DM object
1135: Output Parameters:
1136: + mat - the interpolation
1137: - vec - the scaling (optional)
1139: Level: developer
1141: Notes:
1142: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1143: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1145: For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1146: EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1148: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolationScale()
1150: @*/
1151: PetscErrorCode DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1152: {
1157: PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1158: (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1159: PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1160: return 0;
1161: }
1163: /*@
1164: DMCreateInterpolationScale - Forms L = 1/(R*1) such that diag(L)*R preserves scale and is thus suitable for state (versus residual) restriction.
1166: Input Parameters:
1167: + dac - DM that defines a coarse mesh
1168: . daf - DM that defines a fine mesh
1169: - mat - the restriction (or interpolation operator) from fine to coarse
1171: Output Parameter:
1172: . scale - the scaled vector
1174: Level: developer
1176: Developer Notes:
1177: If the fine-scale DMDA has the -dm_bind_below option set to true, then DMCreateInterpolationScale() calls MatSetBindingPropagates()
1178: on the restriction/interpolation operator to set the bindingpropagates flag to true.
1180: .seealso: DMCreateInterpolation()
1182: @*/
1183: PetscErrorCode DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1184: {
1185: Vec fine;
1186: PetscScalar one = 1.0;
1187: #if defined(PETSC_HAVE_CUDA)
1188: PetscBool bindingpropagates,isbound;
1189: #endif
1191: DMCreateGlobalVector(daf,&fine);
1192: DMCreateGlobalVector(dac,scale);
1193: VecSet(fine,one);
1194: #if defined(PETSC_HAVE_CUDA)
1195: /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1196: * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1197: * we'll need to do it for that case, too.*/
1198: VecGetBindingPropagates(fine,&bindingpropagates);
1199: if (bindingpropagates) {
1200: MatSetBindingPropagates(mat,PETSC_TRUE);
1201: VecBoundToCPU(fine,&isbound);
1202: MatBindToCPU(mat,isbound);
1203: }
1204: #endif
1205: MatRestrict(mat,fine,*scale);
1206: VecDestroy(&fine);
1207: VecReciprocal(*scale);
1208: return 0;
1209: }
1211: /*@
1212: DMCreateRestriction - Gets restriction matrix between two DM objects
1214: Collective on dmc
1216: Input Parameters:
1217: + dmc - the DM object
1218: - dmf - the second, finer DM object
1220: Output Parameter:
1221: . mat - the restriction
1223: Level: developer
1225: Notes:
1226: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1227: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1229: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()
1231: @*/
1232: PetscErrorCode DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1233: {
1238: PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1239: (*dmc->ops->createrestriction)(dmc,dmf,mat);
1240: PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1241: return 0;
1242: }
1244: /*@
1245: DMCreateInjection - Gets injection matrix between two DM objects
1247: Collective on dac
1249: Input Parameters:
1250: + dac - the DM object
1251: - daf - the second, finer DM object
1253: Output Parameter:
1254: . mat - the injection
1256: Level: developer
1258: Notes:
1259: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1260: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
1262: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
1264: @*/
1265: PetscErrorCode DMCreateInjection(DM dac,DM daf,Mat *mat)
1266: {
1271: PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1272: (*dac->ops->createinjection)(dac,daf,mat);
1273: PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1274: return 0;
1275: }
1277: /*@
1278: DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j
1280: Collective on dac
1282: Input Parameters:
1283: + dmc - the target DM object
1284: - dmf - the source DM object
1286: Output Parameter:
1287: . mat - the mass matrix
1289: Level: developer
1291: .seealso DMCreateMassMatrixLumped(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1292: @*/
1293: PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1294: {
1299: (*dmc->ops->createmassmatrix)(dmc, dmf, mat);
1300: return 0;
1301: }
1303: /*@
1304: DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given DM
1306: Collective on dm
1308: Input Parameter:
1309: . dm - the DM object
1311: Output Parameter:
1312: . lm - the lumped mass matrix
1314: Level: developer
1316: .seealso DMCreateMassMatrix(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1317: @*/
1318: PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *lm)
1319: {
1323: (*dm->ops->createmassmatrixlumped)(dm, lm);
1324: return 0;
1325: }
1327: /*@
1328: DMCreateColoring - Gets coloring for a DM
1330: Collective on dm
1332: Input Parameters:
1333: + dm - the DM object
1334: - ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL
1336: Output Parameter:
1337: . coloring - the coloring
1339: Notes:
1340: Coloring of matrices can be computed directly from the sparse matrix nonzero structure via the MatColoring object or from the mesh from which the
1341: matrix comes from. In general using the mesh produces a more optimal coloring (fewer colors).
1343: This produces a coloring with the distance of 2, see MatSetColoringDistance() which can be used for efficiently computing Jacobians with MatFDColoringCreate()
1345: Level: developer
1347: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType(), MatColoring, MatFDColoringCreate()
1349: @*/
1350: PetscErrorCode DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1351: {
1355: (*dm->ops->getcoloring)(dm,ctype,coloring);
1356: return 0;
1357: }
1359: /*@
1360: DMCreateMatrix - Gets empty Jacobian for a DM
1362: Collective on dm
1364: Input Parameter:
1365: . dm - the DM object
1367: Output Parameter:
1368: . mat - the empty Jacobian
1370: Level: beginner
1372: Options Database Keys:
1373: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1375: Notes:
1376: This properly preallocates the number of nonzeros in the sparse matrix so you
1377: do not need to do it yourself.
1379: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1380: the nonzero pattern call DMSetMatrixPreallocateOnly()
1382: For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1383: internally by PETSc.
1385: For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1386: the indices for the global numbering for DMDAs which is complicated.
1388: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1390: @*/
1391: PetscErrorCode DMCreateMatrix(DM dm,Mat *mat)
1392: {
1396: MatInitializePackage();
1397: PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1398: (*dm->ops->creatematrix)(dm,mat);
1399: if (PetscDefined(USE_DEBUG)) {
1400: DM mdm;
1402: MatGetDM(*mat,&mdm);
1404: }
1405: /* Handle nullspace and near nullspace */
1406: if (dm->Nf) {
1407: MatNullSpace nullSpace;
1408: PetscInt Nf, f;
1410: DMGetNumFields(dm, &Nf);
1411: for (f = 0; f < Nf; ++f) {
1412: if (dm->nullspaceConstructors[f]) {
1413: (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1414: MatSetNullSpace(*mat, nullSpace);
1415: MatNullSpaceDestroy(&nullSpace);
1416: break;
1417: }
1418: }
1419: for (f = 0; f < Nf; ++f) {
1420: if (dm->nearnullspaceConstructors[f]) {
1421: (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1422: MatSetNearNullSpace(*mat, nullSpace);
1423: MatNullSpaceDestroy(&nullSpace);
1424: }
1425: }
1426: }
1427: PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1428: return 0;
1429: }
1431: /*@
1432: DMSetMatrixPreallocateSkip - When DMCreateMatrix() is called the matrix sizes and ISLocalToGlobalMapping will be
1433: properly set, but the entries will not be preallocated. This is most useful to reduce initialization costs when
1434: MatSetPreallocationCOO() and MatSetValuesCOO() will be used.
1436: Logically Collective on dm
1438: Input Parameters:
1439: + dm - the DM
1440: - skip - PETSC_TRUE to skip preallocation
1442: Level: developer
1444: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1445: @*/
1446: PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1447: {
1449: dm->prealloc_skip = skip;
1450: return 0;
1451: }
1453: /*@
1454: DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1455: preallocated but the nonzero structure and zero values will not be set.
1457: Logically Collective on dm
1459: Input Parameters:
1460: + dm - the DM
1461: - only - PETSC_TRUE if only want preallocation
1463: Level: developer
1465: Options Database Keys:
1466: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1468: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1469: @*/
1470: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1471: {
1473: dm->prealloc_only = only;
1474: return 0;
1475: }
1477: /*@
1478: DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1479: but the array for values will not be allocated.
1481: Logically Collective on dm
1483: Input Parameters:
1484: + dm - the DM
1485: - only - PETSC_TRUE if only want matrix stucture
1487: Level: developer
1488: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1489: @*/
1490: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1491: {
1493: dm->structure_only = only;
1494: return 0;
1495: }
1497: /*@C
1498: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1500: Not Collective
1502: Input Parameters:
1503: + dm - the DM object
1504: . count - The minimum size
1505: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1507: Output Parameter:
1508: . array - the work array
1510: Level: developer
1512: .seealso DMDestroy(), DMCreate()
1513: @*/
1514: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1515: {
1516: DMWorkLink link;
1517: PetscMPIInt dsize;
1521: if (dm->workin) {
1522: link = dm->workin;
1523: dm->workin = dm->workin->next;
1524: } else {
1525: PetscNewLog(dm,&link);
1526: }
1527: MPI_Type_size(dtype,&dsize);
1528: if (((size_t)dsize*count) > link->bytes) {
1529: PetscFree(link->mem);
1530: PetscMalloc(dsize*count,&link->mem);
1531: link->bytes = dsize*count;
1532: }
1533: link->next = dm->workout;
1534: dm->workout = link;
1535: #if defined(PETSC_HAVE_VALGRIND)
1536: VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1537: VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1538: #endif
1539: *(void**)mem = link->mem;
1540: return 0;
1541: }
1543: /*@C
1544: DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1546: Not Collective
1548: Input Parameters:
1549: + dm - the DM object
1550: . count - The minimum size
1551: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1553: Output Parameter:
1554: . array - the work array
1556: Level: developer
1558: Developer Notes:
1559: count and dtype are ignored, they are only needed for DMGetWorkArray()
1561: .seealso DMDestroy(), DMCreate()
1562: @*/
1563: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1564: {
1565: DMWorkLink *p,link;
1569: for (p=&dm->workout; (link=*p); p=&link->next) {
1570: if (link->mem == *(void**)mem) {
1571: *p = link->next;
1572: link->next = dm->workin;
1573: dm->workin = link;
1574: *(void**)mem = NULL;
1575: return 0;
1576: }
1577: }
1578: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1579: }
1581: /*@C
1582: DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field when function spaces are joined or split, such as in DMCreateSubDM()
1584: Logically collective on DM
1586: Input Parameters:
1587: + dm - The DM
1588: . field - The field number for the nullspace
1589: - nullsp - A callback to create the nullspace
1591: Calling sequence of nullsp:
1592: .vb
1593: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1594: .ve
1595: + dm - The present DM
1596: . origField - The field number given above, in the original DM
1597: . field - The field number in dm
1598: - nullSpace - The nullspace for the given field
1600: This function is currently not available from Fortran.
1602: Level: intermediate
1604: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1605: @*/
1606: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace*))
1607: {
1610: dm->nullspaceConstructors[field] = nullsp;
1611: return 0;
1612: }
1614: /*@C
1615: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL
1617: Not collective
1619: Input Parameters:
1620: + dm - The DM
1621: - field - The field number for the nullspace
1623: Output Parameter:
1624: . nullsp - A callback to create the nullspace
1626: Calling sequence of nullsp:
1627: .vb
1628: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1629: .ve
1630: + dm - The present DM
1631: . origField - The field number given above, in the original DM
1632: . field - The field number in dm
1633: - nullSpace - The nullspace for the given field
1635: This function is currently not available from Fortran.
1637: Level: intermediate
1639: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1640: @*/
1641: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1642: {
1646: *nullsp = dm->nullspaceConstructors[field];
1647: return 0;
1648: }
1650: /*@C
1651: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field
1653: Logically collective on DM
1655: Input Parameters:
1656: + dm - The DM
1657: . field - The field number for the nullspace
1658: - nullsp - A callback to create the near-nullspace
1660: Calling sequence of nullsp:
1661: .vb
1662: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1663: .ve
1664: + dm - The present DM
1665: . origField - The field number given above, in the original DM
1666: . field - The field number in dm
1667: - nullSpace - The nullspace for the given field
1669: This function is currently not available from Fortran.
1671: Level: intermediate
1673: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1674: @*/
1675: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1676: {
1679: dm->nearnullspaceConstructors[field] = nullsp;
1680: return 0;
1681: }
1683: /*@C
1684: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL
1686: Not collective
1688: Input Parameters:
1689: + dm - The DM
1690: - field - The field number for the nullspace
1692: Output Parameter:
1693: . nullsp - A callback to create the near-nullspace
1695: Calling sequence of nullsp:
1696: .vb
1697: PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1698: .ve
1699: + dm - The present DM
1700: . origField - The field number given above, in the original DM
1701: . field - The field number in dm
1702: - nullSpace - The nullspace for the given field
1704: This function is currently not available from Fortran.
1706: Level: intermediate
1708: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1709: @*/
1710: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1711: {
1715: *nullsp = dm->nearnullspaceConstructors[field];
1716: return 0;
1717: }
1719: /*@C
1720: DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1722: Not collective
1724: Input Parameter:
1725: . dm - the DM object
1727: Output Parameters:
1728: + numFields - The number of fields (or NULL if not requested)
1729: . fieldNames - The name for each field (or NULL if not requested)
1730: - fields - The global indices for each field (or NULL if not requested)
1732: Level: intermediate
1734: Notes:
1735: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1736: PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1737: PetscFree().
1739: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1740: @*/
1741: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1742: {
1743: PetscSection section, sectionGlobal;
1746: if (numFields) {
1748: *numFields = 0;
1749: }
1750: if (fieldNames) {
1752: *fieldNames = NULL;
1753: }
1754: if (fields) {
1756: *fields = NULL;
1757: }
1758: DMGetLocalSection(dm, §ion);
1759: if (section) {
1760: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1761: PetscInt nF, f, pStart, pEnd, p;
1763: DMGetGlobalSection(dm, §ionGlobal);
1764: PetscSectionGetNumFields(section, &nF);
1765: PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1766: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1767: for (f = 0; f < nF; ++f) {
1768: fieldSizes[f] = 0;
1769: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1770: }
1771: for (p = pStart; p < pEnd; ++p) {
1772: PetscInt gdof;
1774: PetscSectionGetDof(sectionGlobal, p, &gdof);
1775: if (gdof > 0) {
1776: for (f = 0; f < nF; ++f) {
1777: PetscInt fdof, fcdof, fpdof;
1779: PetscSectionGetFieldDof(section, p, f, &fdof);
1780: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1781: fpdof = fdof-fcdof;
1782: if (fpdof && fpdof != fieldNc[f]) {
1783: /* Layout does not admit a pointwise block size */
1784: fieldNc[f] = 1;
1785: }
1786: fieldSizes[f] += fpdof;
1787: }
1788: }
1789: }
1790: for (f = 0; f < nF; ++f) {
1791: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1792: fieldSizes[f] = 0;
1793: }
1794: for (p = pStart; p < pEnd; ++p) {
1795: PetscInt gdof, goff;
1797: PetscSectionGetDof(sectionGlobal, p, &gdof);
1798: if (gdof > 0) {
1799: PetscSectionGetOffset(sectionGlobal, p, &goff);
1800: for (f = 0; f < nF; ++f) {
1801: PetscInt fdof, fcdof, fc;
1803: PetscSectionGetFieldDof(section, p, f, &fdof);
1804: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1805: for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1806: fieldIndices[f][fieldSizes[f]] = goff++;
1807: }
1808: }
1809: }
1810: }
1811: if (numFields) *numFields = nF;
1812: if (fieldNames) {
1813: PetscMalloc1(nF, fieldNames);
1814: for (f = 0; f < nF; ++f) {
1815: const char *fieldName;
1817: PetscSectionGetFieldName(section, f, &fieldName);
1818: PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1819: }
1820: }
1821: if (fields) {
1822: PetscMalloc1(nF, fields);
1823: for (f = 0; f < nF; ++f) {
1824: PetscInt bs, in[2], out[2];
1826: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1827: in[0] = -fieldNc[f];
1828: in[1] = fieldNc[f];
1829: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1830: bs = (-out[0] == out[1]) ? out[1] : 1;
1831: ISSetBlockSize((*fields)[f], bs);
1832: }
1833: }
1834: PetscFree3(fieldSizes,fieldNc,fieldIndices);
1835: } else if (dm->ops->createfieldis) {
1836: (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1837: }
1838: return 0;
1839: }
1841: /*@C
1842: DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1843: corresponding to different fields: each IS contains the global indices of the dofs of the
1844: corresponding field. The optional list of DMs define the DM for each subproblem.
1845: Generalizes DMCreateFieldIS().
1847: Not collective
1849: Input Parameter:
1850: . dm - the DM object
1852: Output Parameters:
1853: + len - The number of subproblems in the field decomposition (or NULL if not requested)
1854: . namelist - The name for each field (or NULL if not requested)
1855: . islist - The global indices for each field (or NULL if not requested)
1856: - dmlist - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1858: Level: intermediate
1860: Notes:
1861: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1862: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1863: and all of the arrays should be freed with PetscFree().
1865: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1866: @*/
1867: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1868: {
1870: if (len) {
1872: *len = 0;
1873: }
1874: if (namelist) {
1876: *namelist = NULL;
1877: }
1878: if (islist) {
1880: *islist = NULL;
1881: }
1882: if (dmlist) {
1884: *dmlist = NULL;
1885: }
1886: /*
1887: Is it a good idea to apply the following check across all impls?
1888: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1889: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1890: */
1892: if (!dm->ops->createfielddecomposition) {
1893: PetscSection section;
1894: PetscInt numFields, f;
1896: DMGetLocalSection(dm, §ion);
1897: if (section) PetscSectionGetNumFields(section, &numFields);
1898: if (section && numFields && dm->ops->createsubdm) {
1899: if (len) *len = numFields;
1900: if (namelist) PetscMalloc1(numFields,namelist);
1901: if (islist) PetscMalloc1(numFields,islist);
1902: if (dmlist) PetscMalloc1(numFields,dmlist);
1903: for (f = 0; f < numFields; ++f) {
1904: const char *fieldName;
1906: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1907: if (namelist) {
1908: PetscSectionGetFieldName(section, f, &fieldName);
1909: PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1910: }
1911: }
1912: } else {
1913: DMCreateFieldIS(dm, len, namelist, islist);
1914: /* By default there are no DMs associated with subproblems. */
1915: if (dmlist) *dmlist = NULL;
1916: }
1917: } else {
1918: (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1919: }
1920: return 0;
1921: }
1923: /*@
1924: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1925: The fields are defined by DMCreateFieldIS().
1927: Not collective
1929: Input Parameters:
1930: + dm - The DM object
1931: . numFields - The number of fields in this subproblem
1932: - fields - The field numbers of the selected fields
1934: Output Parameters:
1935: + is - The global indices for the subproblem
1936: - subdm - The DM for the subproblem
1938: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1940: Level: intermediate
1942: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1943: @*/
1944: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1945: {
1951: (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1952: return 0;
1953: }
1955: /*@C
1956: DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.
1958: Not collective
1960: Input Parameters:
1961: + dms - The DM objects
1962: - len - The number of DMs
1964: Output Parameters:
1965: + is - The global indices for the subproblem, or NULL
1966: - superdm - The DM for the superproblem
1968: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1970: Level: intermediate
1972: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1973: @*/
1974: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1975: {
1976: PetscInt i;
1983: if (len) {
1984: DM dm = dms[0];
1986: (*dm->ops->createsuperdm)(dms, len, is, superdm);
1987: }
1988: return 0;
1989: }
1991: /*@C
1992: DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1993: corresponding to restrictions to pairs nested subdomains: each IS contains the global
1994: indices of the dofs of the corresponding subdomains. The inner subdomains conceptually
1995: define a nonoverlapping covering, while outer subdomains can overlap.
1996: The optional list of DMs define the DM for each subproblem.
1998: Not collective
2000: Input Parameter:
2001: . dm - the DM object
2003: Output Parameters:
2004: + len - The number of subproblems in the domain decomposition (or NULL if not requested)
2005: . namelist - The name for each subdomain (or NULL if not requested)
2006: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2007: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2008: - dmlist - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
2010: Level: intermediate
2012: Notes:
2013: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
2014: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
2015: and all of the arrays should be freed with PetscFree().
2017: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
2018: @*/
2019: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2020: {
2021: DMSubDomainHookLink link;
2022: PetscInt i,l;
2030: /*
2031: Is it a good idea to apply the following check across all impls?
2032: Perhaps some impls can have a well-defined decomposition before DMSetUp?
2033: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2034: */
2036: if (dm->ops->createdomaindecomposition) {
2037: (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
2038: /* copy subdomain hooks and context over to the subdomain DMs */
2039: if (dmlist && *dmlist) {
2040: for (i = 0; i < l; i++) {
2041: for (link=dm->subdomainhook; link; link=link->next) {
2042: if (link->ddhook) (*link->ddhook)(dm,(*dmlist)[i],link->ctx);
2043: }
2044: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2045: }
2046: }
2047: if (len) *len = l;
2048: }
2049: return 0;
2050: }
2052: /*@C
2053: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
2055: Not collective
2057: Input Parameters:
2058: + dm - the DM object
2059: . n - the number of subdomain scatters
2060: - subdms - the local subdomains
2062: Output Parameters:
2063: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2064: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2065: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2067: Notes:
2068: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2069: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2070: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2071: solution and residual data.
2073: Level: developer
2075: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2076: @*/
2077: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2078: {
2082: (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2083: return 0;
2084: }
2086: /*@
2087: DMRefine - Refines a DM object
2089: Collective on dm
2091: Input Parameters:
2092: + dm - the DM object
2093: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2095: Output Parameter:
2096: . dmf - the refined DM, or NULL
2098: Options Database Keys:
2099: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2101: Note: If no refinement was done, the return value is NULL
2103: Level: developer
2105: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2106: @*/
2107: PetscErrorCode DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2108: {
2109: DMRefineHookLink link;
2113: PetscLogEventBegin(DM_Refine,dm,0,0,0);
2114: (*dm->ops->refine)(dm,comm,dmf);
2115: if (*dmf) {
2116: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2118: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);
2120: (*dmf)->ctx = dm->ctx;
2121: (*dmf)->leveldown = dm->leveldown;
2122: (*dmf)->levelup = dm->levelup + 1;
2124: DMSetMatType(*dmf,dm->mattype);
2125: for (link=dm->refinehook; link; link=link->next) {
2126: if (link->refinehook) {
2127: (*link->refinehook)(dm,*dmf,link->ctx);
2128: }
2129: }
2130: }
2131: PetscLogEventEnd(DM_Refine,dm,0,0,0);
2132: return 0;
2133: }
2135: /*@C
2136: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2138: Logically Collective
2140: Input Parameters:
2141: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2142: . refinehook - function to run when setting up a coarser level
2143: . interphook - function to run to update data on finer levels (once per SNESSolve())
2144: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2146: Calling sequence of refinehook:
2147: $ refinehook(DM coarse,DM fine,void *ctx);
2149: + coarse - coarse level DM
2150: . fine - fine level DM to interpolate problem to
2151: - ctx - optional user-defined function context
2153: Calling sequence for interphook:
2154: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2156: + coarse - coarse level DM
2157: . interp - matrix interpolating a coarse-level solution to the finer grid
2158: . fine - fine level DM to update
2159: - ctx - optional user-defined function context
2161: Level: advanced
2163: Notes:
2164: This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
2166: If this function is called multiple times, the hooks will be run in the order they are added.
2168: This function is currently not available from Fortran.
2170: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2171: @*/
2172: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2173: {
2174: DMRefineHookLink link,*p;
2177: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2178: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return 0;
2179: }
2180: PetscNew(&link);
2181: link->refinehook = refinehook;
2182: link->interphook = interphook;
2183: link->ctx = ctx;
2184: link->next = NULL;
2185: *p = link;
2186: return 0;
2187: }
2189: /*@C
2190: DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
2192: Logically Collective
2194: Input Parameters:
2195: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2196: . refinehook - function to run when setting up a coarser level
2197: . interphook - function to run to update data on finer levels (once per SNESSolve())
2198: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2200: Level: advanced
2202: Notes:
2203: This function does nothing if the hook is not in the list.
2205: This function is currently not available from Fortran.
2207: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2208: @*/
2209: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2210: {
2211: DMRefineHookLink link,*p;
2214: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2215: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2216: link = *p;
2217: *p = link->next;
2218: PetscFree(link);
2219: break;
2220: }
2221: }
2222: return 0;
2223: }
2225: /*@
2226: DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
2228: Collective if any hooks are
2230: Input Parameters:
2231: + coarse - coarser DM to use as a base
2232: . interp - interpolation matrix, apply using MatInterpolate()
2233: - fine - finer DM to update
2235: Level: developer
2237: .seealso: DMRefineHookAdd(), MatInterpolate()
2238: @*/
2239: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2240: {
2241: DMRefineHookLink link;
2243: for (link=fine->refinehook; link; link=link->next) {
2244: if (link->interphook) {
2245: (*link->interphook)(coarse,interp,fine,link->ctx);
2246: }
2247: }
2248: return 0;
2249: }
2251: /*@
2252: DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2254: Collective on DM
2256: Input Parameters:
2257: + coarse - coarse DM
2258: . fine - fine DM
2259: . interp - (optional) the matrix computed by DMCreateInterpolation(). Implementations may not need this, but if it
2260: is available it can avoid some recomputation. If it is provided, MatInterpolate() will be used if
2261: the coarse DM does not have a specialized implementation.
2262: - coarseSol - solution on the coarse mesh
2264: Output Parameter:
2265: . fineSol - the interpolation of coarseSol to the fine mesh
2267: Level: developer
2269: Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2270: map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2271: out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2272: slope-limiting reconstruction.
2274: .seealso DMInterpolate(), DMCreateInterpolation()
2275: @*/
2276: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2277: {
2278: PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;
2285: PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2286: if (interpsol) {
2287: (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2288: } else if (interp) {
2289: MatInterpolate(interp, coarseSol, fineSol);
2290: } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2291: return 0;
2292: }
2294: /*@
2295: DMGetRefineLevel - Gets the number of refinements that have generated this DM.
2297: Not Collective
2299: Input Parameter:
2300: . dm - the DM object
2302: Output Parameter:
2303: . level - number of refinements
2305: Level: developer
2307: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2309: @*/
2310: PetscErrorCode DMGetRefineLevel(DM dm,PetscInt *level)
2311: {
2313: *level = dm->levelup;
2314: return 0;
2315: }
2317: /*@
2318: DMSetRefineLevel - Sets the number of refinements that have generated this DM.
2320: Not Collective
2322: Input Parameters:
2323: + dm - the DM object
2324: - level - number of refinements
2326: Level: advanced
2328: Notes:
2329: This value is used by PCMG to determine how many multigrid levels to use
2331: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2333: @*/
2334: PetscErrorCode DMSetRefineLevel(DM dm,PetscInt level)
2335: {
2337: dm->levelup = level;
2338: return 0;
2339: }
2341: /*@
2342: DMExtrude - Extrude a DM object from a surface
2344: Collective on dm
2346: Input Parameters:
2347: + dm - the DM object
2348: - layers - the number of extruded cell layers
2350: Output Parameter:
2351: . dme - the extruded DM, or NULL
2353: Note: If no extrusion was done, the return value is NULL
2355: Level: developer
2357: .seealso DMRefine(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector()
2358: @*/
2359: PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2360: {
2363: (*dm->ops->extrude)(dm, layers, dme);
2364: if (*dme) {
2365: (*dme)->ops->creatematrix = dm->ops->creatematrix;
2366: PetscObjectCopyFortranFunctionPointers((PetscObject) dm, (PetscObject) *dme);
2367: (*dme)->ctx = dm->ctx;
2368: DMSetMatType(*dme, dm->mattype);
2369: }
2370: return 0;
2371: }
2373: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2374: {
2377: *tdm = dm->transformDM;
2378: return 0;
2379: }
2381: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2382: {
2385: *tv = dm->transform;
2386: return 0;
2387: }
2389: /*@
2390: DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors
2392: Input Parameter:
2393: . dm - The DM
2395: Output Parameter:
2396: . flg - PETSC_TRUE if a basis transformation should be done
2398: Level: developer
2400: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2401: @*/
2402: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2403: {
2404: Vec tv;
2408: DMGetBasisTransformVec_Internal(dm, &tv);
2409: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2410: return 0;
2411: }
2413: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2414: {
2415: PetscSection s, ts;
2416: PetscScalar *ta;
2417: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2419: DMGetCoordinateDim(dm, &cdim);
2420: DMGetLocalSection(dm, &s);
2421: PetscSectionGetChart(s, &pStart, &pEnd);
2422: PetscSectionGetNumFields(s, &Nf);
2423: DMClone(dm, &dm->transformDM);
2424: DMGetLocalSection(dm->transformDM, &ts);
2425: PetscSectionSetNumFields(ts, Nf);
2426: PetscSectionSetChart(ts, pStart, pEnd);
2427: for (f = 0; f < Nf; ++f) {
2428: PetscSectionGetFieldComponents(s, f, &Nc);
2429: /* We could start to label fields by their transformation properties */
2430: if (Nc != cdim) continue;
2431: for (p = pStart; p < pEnd; ++p) {
2432: PetscSectionGetFieldDof(s, p, f, &dof);
2433: if (!dof) continue;
2434: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2435: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2436: }
2437: }
2438: PetscSectionSetUp(ts);
2439: DMCreateLocalVector(dm->transformDM, &dm->transform);
2440: VecGetArray(dm->transform, &ta);
2441: for (p = pStart; p < pEnd; ++p) {
2442: for (f = 0; f < Nf; ++f) {
2443: PetscSectionGetFieldDof(ts, p, f, &dof);
2444: if (dof) {
2445: PetscReal x[3] = {0.0, 0.0, 0.0};
2446: PetscScalar *tva;
2447: const PetscScalar *A;
2449: /* TODO Get quadrature point for this dual basis vector for coordinate */
2450: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2451: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2452: PetscArraycpy(tva, A, PetscSqr(cdim));
2453: }
2454: }
2455: }
2456: VecRestoreArray(dm->transform, &ta);
2457: return 0;
2458: }
2460: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2461: {
2464: newdm->transformCtx = dm->transformCtx;
2465: newdm->transformSetUp = dm->transformSetUp;
2466: newdm->transformDestroy = NULL;
2467: newdm->transformGetMatrix = dm->transformGetMatrix;
2468: if (newdm->transformSetUp) DMConstructBasisTransform_Internal(newdm);
2469: return 0;
2470: }
2472: /*@C
2473: DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
2475: Logically Collective
2477: Input Parameters:
2478: + dm - the DM
2479: . beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2480: . endhook - function to run after DMGlobalToLocalEnd() has completed
2481: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2483: Calling sequence for beginhook:
2484: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2486: + dm - global DM
2487: . g - global vector
2488: . mode - mode
2489: . l - local vector
2490: - ctx - optional user-defined function context
2492: Calling sequence for endhook:
2493: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2495: + global - global DM
2496: - ctx - optional user-defined function context
2498: Level: advanced
2500: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2501: @*/
2502: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2503: {
2504: DMGlobalToLocalHookLink link,*p;
2507: for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2508: PetscNew(&link);
2509: link->beginhook = beginhook;
2510: link->endhook = endhook;
2511: link->ctx = ctx;
2512: link->next = NULL;
2513: *p = link;
2514: return 0;
2515: }
2517: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2518: {
2519: Mat cMat;
2520: Vec cVec, cBias;
2521: PetscSection section, cSec;
2522: PetscInt pStart, pEnd, p, dof;
2525: DMGetDefaultConstraints(dm,&cSec,&cMat,&cBias);
2526: if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2527: PetscInt nRows;
2529: MatGetSize(cMat,&nRows,NULL);
2530: if (nRows <= 0) return 0;
2531: DMGetLocalSection(dm,§ion);
2532: MatCreateVecs(cMat,NULL,&cVec);
2533: MatMult(cMat,l,cVec);
2534: if (cBias) VecAXPY(cVec,1.,cBias);
2535: PetscSectionGetChart(cSec,&pStart,&pEnd);
2536: for (p = pStart; p < pEnd; p++) {
2537: PetscSectionGetDof(cSec,p,&dof);
2538: if (dof) {
2539: PetscScalar *vals;
2540: VecGetValuesSection(cVec,cSec,p,&vals);
2541: VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2542: }
2543: }
2544: VecDestroy(&cVec);
2545: }
2546: return 0;
2547: }
2549: /*@
2550: DMGlobalToLocal - update local vectors from global vector
2552: Neighbor-wise Collective on dm
2554: Input Parameters:
2555: + dm - the DM object
2556: . g - the global vector
2557: . mode - INSERT_VALUES or ADD_VALUES
2558: - l - the local vector
2560: Notes:
2561: The communication involved in this update can be overlapped with computation by using
2562: DMGlobalToLocalBegin() and DMGlobalToLocalEnd().
2564: Level: beginner
2566: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2568: @*/
2569: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2570: {
2571: DMGlobalToLocalBegin(dm,g,mode,l);
2572: DMGlobalToLocalEnd(dm,g,mode,l);
2573: return 0;
2574: }
2576: /*@
2577: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2579: Neighbor-wise Collective on dm
2581: Input Parameters:
2582: + dm - the DM object
2583: . g - the global vector
2584: . mode - INSERT_VALUES or ADD_VALUES
2585: - l - the local vector
2587: Level: intermediate
2589: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2591: @*/
2592: PetscErrorCode DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2593: {
2594: PetscSF sf;
2595: DMGlobalToLocalHookLink link;
2598: for (link=dm->gtolhook; link; link=link->next) {
2599: if (link->beginhook) {
2600: (*link->beginhook)(dm,g,mode,l,link->ctx);
2601: }
2602: }
2603: DMGetSectionSF(dm, &sf);
2604: if (sf) {
2605: const PetscScalar *gArray;
2606: PetscScalar *lArray;
2607: PetscMemType lmtype,gmtype;
2610: VecGetArrayAndMemType(l, &lArray, &lmtype);
2611: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2612: PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2613: VecRestoreArrayAndMemType(l, &lArray);
2614: VecRestoreArrayReadAndMemType(g, &gArray);
2615: } else {
2617: (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2618: }
2619: return 0;
2620: }
2622: /*@
2623: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2625: Neighbor-wise Collective on dm
2627: Input Parameters:
2628: + dm - the DM object
2629: . g - the global vector
2630: . mode - INSERT_VALUES or ADD_VALUES
2631: - l - the local vector
2633: Level: intermediate
2635: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2637: @*/
2638: PetscErrorCode DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2639: {
2640: PetscSF sf;
2641: const PetscScalar *gArray;
2642: PetscScalar *lArray;
2643: PetscBool transform;
2644: DMGlobalToLocalHookLink link;
2645: PetscMemType lmtype,gmtype;
2648: DMGetSectionSF(dm, &sf);
2649: DMHasBasisTransform(dm, &transform);
2650: if (sf) {
2653: VecGetArrayAndMemType(l, &lArray, &lmtype);
2654: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2655: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2656: VecRestoreArrayAndMemType(l, &lArray);
2657: VecRestoreArrayReadAndMemType(g, &gArray);
2658: if (transform) DMPlexGlobalToLocalBasis(dm, l);
2659: } else {
2661: (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2662: }
2663: DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2664: for (link=dm->gtolhook; link; link=link->next) {
2665: if (link->endhook) (*link->endhook)(dm,g,mode,l,link->ctx);
2666: }
2667: return 0;
2668: }
2670: /*@C
2671: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2673: Logically Collective
2675: Input Parameters:
2676: + dm - the DM
2677: . beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2678: . endhook - function to run after DMLocalToGlobalEnd() has completed
2679: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2681: Calling sequence for beginhook:
2682: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2684: + dm - global DM
2685: . l - local vector
2686: . mode - mode
2687: . g - global vector
2688: - ctx - optional user-defined function context
2690: Calling sequence for endhook:
2691: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2693: + global - global DM
2694: . l - local vector
2695: . mode - mode
2696: . g - global vector
2697: - ctx - optional user-defined function context
2699: Level: advanced
2701: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2702: @*/
2703: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2704: {
2705: DMLocalToGlobalHookLink link,*p;
2708: for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2709: PetscNew(&link);
2710: link->beginhook = beginhook;
2711: link->endhook = endhook;
2712: link->ctx = ctx;
2713: link->next = NULL;
2714: *p = link;
2715: return 0;
2716: }
2718: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2719: {
2720: Mat cMat;
2721: Vec cVec;
2722: PetscSection section, cSec;
2723: PetscInt pStart, pEnd, p, dof;
2726: DMGetDefaultConstraints(dm,&cSec,&cMat,NULL);
2727: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2728: PetscInt nRows;
2730: MatGetSize(cMat,&nRows,NULL);
2731: if (nRows <= 0) return 0;
2732: DMGetLocalSection(dm,§ion);
2733: MatCreateVecs(cMat,NULL,&cVec);
2734: PetscSectionGetChart(cSec,&pStart,&pEnd);
2735: for (p = pStart; p < pEnd; p++) {
2736: PetscSectionGetDof(cSec,p,&dof);
2737: if (dof) {
2738: PetscInt d;
2739: PetscScalar *vals;
2740: VecGetValuesSection(l,section,p,&vals);
2741: VecSetValuesSection(cVec,cSec,p,vals,mode);
2742: /* for this to be the true transpose, we have to zero the values that
2743: * we just extracted */
2744: for (d = 0; d < dof; d++) {
2745: vals[d] = 0.;
2746: }
2747: }
2748: }
2749: MatMultTransposeAdd(cMat,cVec,l,l);
2750: VecDestroy(&cVec);
2751: }
2752: return 0;
2753: }
2754: /*@
2755: DMLocalToGlobal - updates global vectors from local vectors
2757: Neighbor-wise Collective on dm
2759: Input Parameters:
2760: + dm - the DM object
2761: . l - the local vector
2762: . 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.
2763: - g - the global vector
2765: Notes:
2766: The communication involved in this update can be overlapped with computation by using
2767: DMLocalToGlobalBegin() and DMLocalToGlobalEnd().
2769: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2770: INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.
2772: Level: beginner
2774: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2776: @*/
2777: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2778: {
2779: DMLocalToGlobalBegin(dm,l,mode,g);
2780: DMLocalToGlobalEnd(dm,l,mode,g);
2781: return 0;
2782: }
2784: /*@
2785: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2787: Neighbor-wise Collective on dm
2789: Input Parameters:
2790: + dm - the DM object
2791: . l - the local vector
2792: . 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.
2793: - g - the global vector
2795: Notes:
2796: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2797: INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2799: Level: intermediate
2801: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2803: @*/
2804: PetscErrorCode DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2805: {
2806: PetscSF sf;
2807: PetscSection s, gs;
2808: DMLocalToGlobalHookLink link;
2809: Vec tmpl;
2810: const PetscScalar *lArray;
2811: PetscScalar *gArray;
2812: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2813: PetscMemType lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;
2816: for (link=dm->ltoghook; link; link=link->next) {
2817: if (link->beginhook) {
2818: (*link->beginhook)(dm,l,mode,g,link->ctx);
2819: }
2820: }
2821: DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2822: DMGetSectionSF(dm, &sf);
2823: DMGetLocalSection(dm, &s);
2824: switch (mode) {
2825: case INSERT_VALUES:
2826: case INSERT_ALL_VALUES:
2827: case INSERT_BC_VALUES:
2828: isInsert = PETSC_TRUE; break;
2829: case ADD_VALUES:
2830: case ADD_ALL_VALUES:
2831: case ADD_BC_VALUES:
2832: isInsert = PETSC_FALSE; break;
2833: default:
2834: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2835: }
2836: if ((sf && !isInsert) || (s && isInsert)) {
2837: DMHasBasisTransform(dm, &transform);
2838: if (transform) {
2839: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2840: VecCopy(l, tmpl);
2841: DMPlexLocalToGlobalBasis(dm, tmpl);
2842: VecGetArrayRead(tmpl, &lArray);
2843: } else if (isInsert) {
2844: VecGetArrayRead(l, &lArray);
2845: } else {
2846: VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2847: l_inplace = PETSC_TRUE;
2848: }
2849: if (s && isInsert) {
2850: VecGetArray(g, &gArray);
2851: } else {
2852: VecGetArrayAndMemType(g, &gArray, &gmtype);
2853: g_inplace = PETSC_TRUE;
2854: }
2855: if (sf && !isInsert) {
2856: PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2857: } else if (s && isInsert) {
2858: PetscInt gStart, pStart, pEnd, p;
2860: DMGetGlobalSection(dm, &gs);
2861: PetscSectionGetChart(s, &pStart, &pEnd);
2862: VecGetOwnershipRange(g, &gStart, NULL);
2863: for (p = pStart; p < pEnd; ++p) {
2864: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2866: PetscSectionGetDof(s, p, &dof);
2867: PetscSectionGetDof(gs, p, &gdof);
2868: PetscSectionGetConstraintDof(s, p, &cdof);
2869: PetscSectionGetConstraintDof(gs, p, &gcdof);
2870: PetscSectionGetOffset(s, p, &off);
2871: PetscSectionGetOffset(gs, p, &goff);
2872: /* Ignore off-process data and points with no global data */
2873: if (!gdof || goff < 0) continue;
2875: /* If no constraints are enforced in the global vector */
2876: if (!gcdof) {
2877: for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2878: /* If constraints are enforced in the global vector */
2879: } else if (cdof == gcdof) {
2880: const PetscInt *cdofs;
2881: PetscInt cind = 0;
2883: PetscSectionGetConstraintIndices(s, p, &cdofs);
2884: for (d = 0, e = 0; d < dof; ++d) {
2885: if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2886: gArray[goff-gStart+e++] = lArray[off+d];
2887: }
2888: } 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);
2889: }
2890: }
2891: if (g_inplace) {
2892: VecRestoreArrayAndMemType(g, &gArray);
2893: } else {
2894: VecRestoreArray(g, &gArray);
2895: }
2896: if (transform) {
2897: VecRestoreArrayRead(tmpl, &lArray);
2898: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2899: } else if (l_inplace) {
2900: VecRestoreArrayReadAndMemType(l, &lArray);
2901: } else {
2902: VecRestoreArrayRead(l, &lArray);
2903: }
2904: } else {
2906: (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2907: }
2908: return 0;
2909: }
2911: /*@
2912: DMLocalToGlobalEnd - updates global vectors from local vectors
2914: Neighbor-wise Collective on dm
2916: Input Parameters:
2917: + dm - the DM object
2918: . l - the local vector
2919: . mode - INSERT_VALUES or ADD_VALUES
2920: - g - the global vector
2922: Level: intermediate
2924: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2926: @*/
2927: PetscErrorCode DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2928: {
2929: PetscSF sf;
2930: PetscSection s;
2931: DMLocalToGlobalHookLink link;
2932: PetscBool isInsert, transform;
2935: DMGetSectionSF(dm, &sf);
2936: DMGetLocalSection(dm, &s);
2937: switch (mode) {
2938: case INSERT_VALUES:
2939: case INSERT_ALL_VALUES:
2940: isInsert = PETSC_TRUE; break;
2941: case ADD_VALUES:
2942: case ADD_ALL_VALUES:
2943: isInsert = PETSC_FALSE; break;
2944: default:
2945: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2946: }
2947: if (sf && !isInsert) {
2948: const PetscScalar *lArray;
2949: PetscScalar *gArray;
2950: Vec tmpl;
2952: DMHasBasisTransform(dm, &transform);
2953: if (transform) {
2954: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2955: VecGetArrayRead(tmpl, &lArray);
2956: } else {
2957: VecGetArrayReadAndMemType(l, &lArray, NULL);
2958: }
2959: VecGetArrayAndMemType(g, &gArray, NULL);
2960: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2961: if (transform) {
2962: VecRestoreArrayRead(tmpl, &lArray);
2963: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2964: } else {
2965: VecRestoreArrayReadAndMemType(l, &lArray);
2966: }
2967: VecRestoreArrayAndMemType(g, &gArray);
2968: } else if (s && isInsert) {
2969: } else {
2971: (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2972: }
2973: for (link=dm->ltoghook; link; link=link->next) {
2974: if (link->endhook) (*link->endhook)(dm,g,mode,l,link->ctx);
2975: }
2976: return 0;
2977: }
2979: /*@
2980: DMLocalToLocalBegin - Maps from a local vector (including ghost points
2981: that contain irrelevant values) to another local vector where the ghost
2982: points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2984: Neighbor-wise Collective on dm
2986: Input Parameters:
2987: + dm - the DM object
2988: . g - the original local vector
2989: - mode - one of INSERT_VALUES or ADD_VALUES
2991: Output Parameter:
2992: . l - the local vector with correct ghost values
2994: Level: intermediate
2996: Notes:
2997: The local vectors used here need not be the same as those
2998: obtained from DMCreateLocalVector(), BUT they
2999: must have the same parallel data layout; they could, for example, be
3000: obtained with VecDuplicate() from the DM originating vectors.
3002: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3004: @*/
3005: PetscErrorCode DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
3006: {
3009: (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3010: return 0;
3011: }
3013: /*@
3014: DMLocalToLocalEnd - Maps from a local vector (including ghost points
3015: that contain irrelevant values) to another local vector where the ghost
3016: points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
3018: Neighbor-wise Collective on dm
3020: Input Parameters:
3021: + da - the DM object
3022: . g - the original local vector
3023: - mode - one of INSERT_VALUES or ADD_VALUES
3025: Output Parameter:
3026: . l - the local vector with correct ghost values
3028: Level: intermediate
3030: Notes:
3031: The local vectors used here need not be the same as those
3032: obtained from DMCreateLocalVector(), BUT they
3033: must have the same parallel data layout; they could, for example, be
3034: obtained with VecDuplicate() from the DM originating vectors.
3036: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3038: @*/
3039: PetscErrorCode DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3040: {
3043: (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3044: return 0;
3045: }
3047: /*@
3048: DMCoarsen - Coarsens a DM object
3050: Collective on dm
3052: Input Parameters:
3053: + dm - the DM object
3054: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
3056: Output Parameter:
3057: . dmc - the coarsened DM
3059: Level: developer
3061: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3063: @*/
3064: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3065: {
3066: DMCoarsenHookLink link;
3070: PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3071: (*dm->ops->coarsen)(dm, comm, dmc);
3072: if (*dmc) {
3073: (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3074: DMSetCoarseDM(dm,*dmc);
3075: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3076: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3077: (*dmc)->ctx = dm->ctx;
3078: (*dmc)->levelup = dm->levelup;
3079: (*dmc)->leveldown = dm->leveldown + 1;
3080: DMSetMatType(*dmc,dm->mattype);
3081: for (link=dm->coarsenhook; link; link=link->next) {
3082: if (link->coarsenhook) (*link->coarsenhook)(dm,*dmc,link->ctx);
3083: }
3084: }
3085: PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3087: return 0;
3088: }
3090: /*@C
3091: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3093: Logically Collective
3095: Input Parameters:
3096: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3097: . coarsenhook - function to run when setting up a coarser level
3098: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3099: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3101: Calling sequence of coarsenhook:
3102: $ coarsenhook(DM fine,DM coarse,void *ctx);
3104: + fine - fine level DM
3105: . coarse - coarse level DM to restrict problem to
3106: - ctx - optional user-defined function context
3108: Calling sequence for restricthook:
3109: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3111: + fine - fine level DM
3112: . mrestrict - matrix restricting a fine-level solution to the coarse grid
3113: . rscale - scaling vector for restriction
3114: . inject - matrix restricting by injection
3115: . coarse - coarse level DM to update
3116: - ctx - optional user-defined function context
3118: Level: advanced
3120: Notes:
3121: This function is only needed if auxiliary data needs to be set up on coarse grids.
3123: If this function is called multiple times, the hooks will be run in the order they are added.
3125: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3126: extract the finest level information from its context (instead of from the SNES).
3128: This function is currently not available from Fortran.
3130: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3131: @*/
3132: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3133: {
3134: DMCoarsenHookLink link,*p;
3137: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3138: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3139: }
3140: PetscNew(&link);
3141: link->coarsenhook = coarsenhook;
3142: link->restricthook = restricthook;
3143: link->ctx = ctx;
3144: link->next = NULL;
3145: *p = link;
3146: return 0;
3147: }
3149: /*@C
3150: DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
3152: Logically Collective
3154: Input Parameters:
3155: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3156: . coarsenhook - function to run when setting up a coarser level
3157: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3158: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3160: Level: advanced
3162: Notes:
3163: This function does nothing if the hook is not in the list.
3165: This function is currently not available from Fortran.
3167: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3168: @*/
3169: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3170: {
3171: DMCoarsenHookLink link,*p;
3174: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3175: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3176: link = *p;
3177: *p = link->next;
3178: PetscFree(link);
3179: break;
3180: }
3181: }
3182: return 0;
3183: }
3185: /*@
3186: DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
3188: Collective if any hooks are
3190: Input Parameters:
3191: + fine - finer DM to use as a base
3192: . restrct - restriction matrix, apply using MatRestrict()
3193: . rscale - scaling vector for restriction
3194: . inject - injection matrix, also use MatRestrict()
3195: - coarse - coarser DM to update
3197: Level: developer
3199: .seealso: DMCoarsenHookAdd(), MatRestrict()
3200: @*/
3201: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3202: {
3203: DMCoarsenHookLink link;
3205: for (link=fine->coarsenhook; link; link=link->next) {
3206: if (link->restricthook) {
3207: (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3208: }
3209: }
3210: return 0;
3211: }
3213: /*@C
3214: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3216: Logically Collective on global
3218: Input Parameters:
3219: + global - global DM
3220: . ddhook - function to run to pass data to the decomposition DM upon its creation
3221: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3222: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3224: Calling sequence for ddhook:
3225: $ ddhook(DM global,DM block,void *ctx)
3227: + global - global DM
3228: . block - block DM
3229: - ctx - optional user-defined function context
3231: Calling sequence for restricthook:
3232: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3234: + global - global DM
3235: . out - scatter to the outer (with ghost and overlap points) block vector
3236: . in - scatter to block vector values only owned locally
3237: . block - block DM
3238: - ctx - optional user-defined function context
3240: Level: advanced
3242: Notes:
3243: This function is only needed if auxiliary data needs to be set up on subdomain DMs.
3245: If this function is called multiple times, the hooks will be run in the order they are added.
3247: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3248: extract the global information from its context (instead of from the SNES).
3250: This function is currently not available from Fortran.
3252: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3253: @*/
3254: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3255: {
3256: DMSubDomainHookLink link,*p;
3259: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3260: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3261: }
3262: PetscNew(&link);
3263: link->restricthook = restricthook;
3264: link->ddhook = ddhook;
3265: link->ctx = ctx;
3266: link->next = NULL;
3267: *p = link;
3268: return 0;
3269: }
3271: /*@C
3272: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3274: Logically Collective
3276: Input Parameters:
3277: + global - global DM
3278: . ddhook - function to run to pass data to the decomposition DM upon its creation
3279: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3280: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3282: Level: advanced
3284: Notes:
3286: This function is currently not available from Fortran.
3288: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3289: @*/
3290: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3291: {
3292: DMSubDomainHookLink link,*p;
3295: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3296: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3297: link = *p;
3298: *p = link->next;
3299: PetscFree(link);
3300: break;
3301: }
3302: }
3303: return 0;
3304: }
3306: /*@
3307: DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
3309: Collective if any hooks are
3311: Input Parameters:
3312: + fine - finer DM to use as a base
3313: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3314: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3315: - coarse - coarer DM to update
3317: Level: developer
3319: .seealso: DMCoarsenHookAdd(), MatRestrict()
3320: @*/
3321: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3322: {
3323: DMSubDomainHookLink link;
3325: for (link=global->subdomainhook; link; link=link->next) {
3326: if (link->restricthook) {
3327: (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3328: }
3329: }
3330: return 0;
3331: }
3333: /*@
3334: DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
3336: Not Collective
3338: Input Parameter:
3339: . dm - the DM object
3341: Output Parameter:
3342: . level - number of coarsenings
3344: Level: developer
3346: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3348: @*/
3349: PetscErrorCode DMGetCoarsenLevel(DM dm,PetscInt *level)
3350: {
3353: *level = dm->leveldown;
3354: return 0;
3355: }
3357: /*@
3358: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
3360: Not Collective
3362: Input Parameters:
3363: + dm - the DM object
3364: - level - number of coarsenings
3366: Level: developer
3368: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3369: @*/
3370: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3371: {
3373: dm->leveldown = level;
3374: return 0;
3375: }
3377: /*@C
3378: DMRefineHierarchy - Refines a DM object, all levels at once
3380: Collective on dm
3382: Input Parameters:
3383: + dm - the DM object
3384: - nlevels - the number of levels of refinement
3386: Output Parameter:
3387: . dmf - the refined DM hierarchy
3389: Level: developer
3391: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3393: @*/
3394: PetscErrorCode DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3395: {
3398: if (nlevels == 0) return 0;
3400: if (dm->ops->refinehierarchy) {
3401: (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3402: } else if (dm->ops->refine) {
3403: PetscInt i;
3405: DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3406: for (i=1; i<nlevels; i++) {
3407: DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3408: }
3409: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3410: return 0;
3411: }
3413: /*@C
3414: DMCoarsenHierarchy - Coarsens a DM object, all levels at once
3416: Collective on dm
3418: Input Parameters:
3419: + dm - the DM object
3420: - nlevels - the number of levels of coarsening
3422: Output Parameter:
3423: . dmc - the coarsened DM hierarchy
3425: Level: developer
3427: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3429: @*/
3430: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3431: {
3434: if (nlevels == 0) return 0;
3436: if (dm->ops->coarsenhierarchy) {
3437: (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3438: } else if (dm->ops->coarsen) {
3439: PetscInt i;
3441: DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3442: for (i=1; i<nlevels; i++) {
3443: DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3444: }
3445: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3446: return 0;
3447: }
3449: /*@C
3450: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
3452: Not Collective
3454: Input Parameters:
3455: + dm - the DM object
3456: - destroy - the destroy function
3458: Level: intermediate
3460: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3462: @*/
3463: PetscErrorCode DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3464: {
3466: dm->ctxdestroy = destroy;
3467: return 0;
3468: }
3470: /*@
3471: DMSetApplicationContext - Set a user context into a DM object
3473: Not Collective
3475: Input Parameters:
3476: + dm - the DM object
3477: - ctx - the user context
3479: Level: intermediate
3481: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3483: @*/
3484: PetscErrorCode DMSetApplicationContext(DM dm,void *ctx)
3485: {
3487: dm->ctx = ctx;
3488: return 0;
3489: }
3491: /*@
3492: DMGetApplicationContext - Gets a user context from a DM object
3494: Not Collective
3496: Input Parameter:
3497: . dm - the DM object
3499: Output Parameter:
3500: . ctx - the user context
3502: Level: intermediate
3504: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3506: @*/
3507: PetscErrorCode DMGetApplicationContext(DM dm,void *ctx)
3508: {
3510: *(void**)ctx = dm->ctx;
3511: return 0;
3512: }
3514: /*@C
3515: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3517: Logically Collective on dm
3519: Input Parameters:
3520: + dm - the DM object
3521: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3523: Level: intermediate
3525: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3526: DMSetJacobian()
3528: @*/
3529: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3530: {
3532: dm->ops->computevariablebounds = f;
3533: return 0;
3534: }
3536: /*@
3537: DMHasVariableBounds - does the DM object have a variable bounds function?
3539: Not Collective
3541: Input Parameter:
3542: . dm - the DM object to destroy
3544: Output Parameter:
3545: . flg - PETSC_TRUE if the variable bounds function exists
3547: Level: developer
3549: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3551: @*/
3552: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3553: {
3556: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3557: return 0;
3558: }
3560: /*@C
3561: DMComputeVariableBounds - compute variable bounds used by SNESVI.
3563: Logically Collective on dm
3565: Input Parameter:
3566: . dm - the DM object
3568: Output parameters:
3569: + xl - lower bound
3570: - xu - upper bound
3572: Level: advanced
3574: Notes:
3575: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3577: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3579: @*/
3580: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3581: {
3586: (*dm->ops->computevariablebounds)(dm, xl,xu);
3587: return 0;
3588: }
3590: /*@
3591: DMHasColoring - does the DM object have a method of providing a coloring?
3593: Not Collective
3595: Input Parameter:
3596: . dm - the DM object
3598: Output Parameter:
3599: . flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3601: Level: developer
3603: .seealso DMCreateColoring()
3605: @*/
3606: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3607: {
3610: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3611: return 0;
3612: }
3614: /*@
3615: DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3617: Not Collective
3619: Input Parameter:
3620: . dm - the DM object
3622: Output Parameter:
3623: . flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3625: Level: developer
3627: .seealso DMCreateRestriction()
3629: @*/
3630: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3631: {
3634: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3635: return 0;
3636: }
3638: /*@
3639: DMHasCreateInjection - does the DM object have a method of providing an injection?
3641: Not Collective
3643: Input Parameter:
3644: . dm - the DM object
3646: Output Parameter:
3647: . flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3649: Level: developer
3651: .seealso DMCreateInjection()
3653: @*/
3654: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3655: {
3658: if (dm->ops->hascreateinjection) {
3659: (*dm->ops->hascreateinjection)(dm,flg);
3660: } else {
3661: *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3662: }
3663: return 0;
3664: }
3666: PetscFunctionList DMList = NULL;
3667: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3669: /*@C
3670: DMSetType - Builds a DM, for a particular DM implementation.
3672: Collective on dm
3674: Input Parameters:
3675: + dm - The DM object
3676: - method - The name of the DM type
3678: Options Database Key:
3679: . -dm_type <type> - Sets the DM type; use -help for a list of available types
3681: Notes:
3682: See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3684: Level: intermediate
3686: .seealso: DMGetType(), DMCreate()
3687: @*/
3688: PetscErrorCode DMSetType(DM dm, DMType method)
3689: {
3690: PetscErrorCode (*r)(DM);
3691: PetscBool match;
3694: PetscObjectTypeCompare((PetscObject) dm, method, &match);
3695: if (match) return 0;
3697: DMRegisterAll();
3698: PetscFunctionListFind(DMList,method,&r);
3701: if (dm->ops->destroy) {
3702: (*dm->ops->destroy)(dm);
3703: }
3704: PetscMemzero(dm->ops,sizeof(*dm->ops));
3705: PetscObjectChangeTypeName((PetscObject)dm,method);
3706: (*r)(dm);
3707: return 0;
3708: }
3710: /*@C
3711: DMGetType - Gets the DM type name (as a string) from the DM.
3713: Not Collective
3715: Input Parameter:
3716: . dm - The DM
3718: Output Parameter:
3719: . type - The DM type name
3721: Level: intermediate
3723: .seealso: DMSetType(), DMCreate()
3724: @*/
3725: PetscErrorCode DMGetType(DM dm, DMType *type)
3726: {
3729: DMRegisterAll();
3730: *type = ((PetscObject)dm)->type_name;
3731: return 0;
3732: }
3734: /*@C
3735: DMConvert - Converts a DM to another DM, either of the same or different type.
3737: Collective on dm
3739: Input Parameters:
3740: + dm - the DM
3741: - newtype - new DM type (use "same" for the same type)
3743: Output Parameter:
3744: . M - pointer to new DM
3746: Notes:
3747: Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3748: the MPI communicator of the generated DM is always the same as the communicator
3749: of the input DM.
3751: Level: intermediate
3753: .seealso: DMCreate()
3754: @*/
3755: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3756: {
3757: DM B;
3758: char convname[256];
3759: PetscBool sametype/*, issame */;
3764: PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3765: /* PetscStrcmp(newtype, "same", &issame); */
3766: if (sametype) {
3767: *M = dm;
3768: PetscObjectReference((PetscObject) dm);
3769: return 0;
3770: } else {
3771: PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3773: /*
3774: Order of precedence:
3775: 1) See if a specialized converter is known to the current DM.
3776: 2) See if a specialized converter is known to the desired DM class.
3777: 3) See if a good general converter is registered for the desired class
3778: 4) See if a good general converter is known for the current matrix.
3779: 5) Use a really basic converter.
3780: */
3782: /* 1) See if a specialized converter is known to the current DM and the desired class */
3783: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3784: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3785: PetscStrlcat(convname,"_",sizeof(convname));
3786: PetscStrlcat(convname,newtype,sizeof(convname));
3787: PetscStrlcat(convname,"_C",sizeof(convname));
3788: PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3789: if (conv) goto foundconv;
3791: /* 2) See if a specialized converter is known to the desired DM class. */
3792: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3793: DMSetType(B, newtype);
3794: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3795: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3796: PetscStrlcat(convname,"_",sizeof(convname));
3797: PetscStrlcat(convname,newtype,sizeof(convname));
3798: PetscStrlcat(convname,"_C",sizeof(convname));
3799: PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3800: if (conv) {
3801: DMDestroy(&B);
3802: goto foundconv;
3803: }
3805: #if 0
3806: /* 3) See if a good general converter is registered for the desired class */
3807: conv = B->ops->convertfrom;
3808: DMDestroy(&B);
3809: if (conv) goto foundconv;
3811: /* 4) See if a good general converter is known for the current matrix */
3812: if (dm->ops->convert) {
3813: conv = dm->ops->convert;
3814: }
3815: if (conv) goto foundconv;
3816: #endif
3818: /* 5) Use a really basic converter. */
3819: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3821: foundconv:
3822: PetscLogEventBegin(DM_Convert,dm,0,0,0);
3823: (*conv)(dm,newtype,M);
3824: /* Things that are independent of DM type: We should consult DMClone() here */
3825: {
3826: PetscBool isper;
3827: const PetscReal *maxCell, *L;
3828: const DMBoundaryType *bd;
3829: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3830: DMSetPeriodicity(*M, isper, maxCell, L, bd);
3831: (*M)->prealloc_only = dm->prealloc_only;
3832: PetscFree((*M)->vectype);
3833: PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3834: PetscFree((*M)->mattype);
3835: PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3836: }
3837: PetscLogEventEnd(DM_Convert,dm,0,0,0);
3838: }
3839: PetscObjectStateIncrease((PetscObject) *M);
3840: return 0;
3841: }
3843: /*--------------------------------------------------------------------------------------------------------------------*/
3845: /*@C
3846: DMRegister - Adds a new DM component implementation
3848: Not Collective
3850: Input Parameters:
3851: + name - The name of a new user-defined creation routine
3852: - create_func - The creation routine itself
3854: Notes:
3855: DMRegister() may be called multiple times to add several user-defined DMs
3857: Sample usage:
3858: .vb
3859: DMRegister("my_da", MyDMCreate);
3860: .ve
3862: Then, your DM type can be chosen with the procedural interface via
3863: .vb
3864: DMCreate(MPI_Comm, DM *);
3865: DMSetType(DM,"my_da");
3866: .ve
3867: or at runtime via the option
3868: .vb
3869: -da_type my_da
3870: .ve
3872: Level: advanced
3874: .seealso: DMRegisterAll(), DMRegisterDestroy()
3876: @*/
3877: PetscErrorCode DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3878: {
3879: DMInitializePackage();
3880: PetscFunctionListAdd(&DMList,sname,function);
3881: return 0;
3882: }
3884: /*@C
3885: DMLoad - Loads a DM that has been stored in binary with DMView().
3887: Collective on viewer
3889: Input Parameters:
3890: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3891: some related function before a call to DMLoad().
3892: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3893: HDF5 file viewer, obtained from PetscViewerHDF5Open()
3895: Level: intermediate
3897: Notes:
3898: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3900: Using PETSCVIEWERHDF5 type with PETSC_VIEWER_HDF5_PETSC format, one can save multiple DMPlex
3901: meshes in a single HDF5 file. This in turn requires one to name the DMPlex object with PetscObjectSetName()
3902: before saving it with DMView() and before loading it with DMLoad() for identification of the mesh object.
3904: Notes for advanced users:
3905: Most users should not need to know the details of the binary storage
3906: format, since DMLoad() and DMView() completely hide these details.
3907: But for anyone who's interested, the standard binary matrix storage
3908: format is
3909: .vb
3910: has not yet been determined
3911: .ve
3913: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3914: @*/
3915: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
3916: {
3917: PetscBool isbinary, ishdf5;
3921: PetscViewerCheckReadable(viewer);
3922: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3923: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3924: PetscLogEventBegin(DM_Load,viewer,0,0,0);
3925: if (isbinary) {
3926: PetscInt classid;
3927: char type[256];
3929: PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3931: PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3932: DMSetType(newdm, type);
3933: if (newdm->ops->load) (*newdm->ops->load)(newdm,viewer);
3934: } else if (ishdf5) {
3935: if (newdm->ops->load) (*newdm->ops->load)(newdm,viewer);
3936: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3937: PetscLogEventEnd(DM_Load,viewer,0,0,0);
3938: return 0;
3939: }
3941: /*@
3942: DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
3944: Not collective
3946: Input Parameter:
3947: . dm - the DM
3949: Output Parameters:
3950: + lmin - local minimum coordinates (length coord dim, optional)
3951: - lmax - local maximim coordinates (length coord dim, optional)
3953: Level: beginner
3955: Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
3957: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3958: @*/
3959: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3960: {
3961: Vec coords = NULL;
3962: PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3963: PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3964: const PetscScalar *local_coords;
3965: PetscInt N, Ni;
3966: PetscInt cdim, i, j;
3969: DMGetCoordinateDim(dm, &cdim);
3970: DMGetCoordinates(dm, &coords);
3971: if (coords) {
3972: VecGetArrayRead(coords, &local_coords);
3973: VecGetLocalSize(coords, &N);
3974: Ni = N/cdim;
3975: for (i = 0; i < Ni; ++i) {
3976: for (j = 0; j < 3; ++j) {
3977: min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3978: max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3979: }
3980: }
3981: VecRestoreArrayRead(coords, &local_coords);
3982: } else {
3983: PetscBool isda;
3985: PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3986: if (isda) DMGetLocalBoundingIndices_DMDA(dm, min, max);
3987: }
3988: if (lmin) PetscArraycpy(lmin, min, cdim);
3989: if (lmax) PetscArraycpy(lmax, max, cdim);
3990: return 0;
3991: }
3993: /*@
3994: DMGetBoundingBox - Returns the global bounding box for the DM.
3996: Collective
3998: Input Parameter:
3999: . dm - the DM
4001: Output Parameters:
4002: + gmin - global minimum coordinates (length coord dim, optional)
4003: - gmax - global maximim coordinates (length coord dim, optional)
4005: Level: beginner
4007: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4008: @*/
4009: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4010: {
4011: PetscReal lmin[3], lmax[3];
4012: PetscInt cdim;
4013: PetscMPIInt count;
4016: DMGetCoordinateDim(dm, &cdim);
4017: PetscMPIIntCast(cdim, &count);
4018: DMGetLocalBoundingBox(dm, lmin, lmax);
4019: if (gmin) MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));
4020: if (gmax) MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));
4021: return 0;
4022: }
4024: /******************************** FEM Support **********************************/
4026: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4027: {
4028: PetscInt f;
4030: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4031: for (f = 0; f < len; ++f) {
4032: PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
4033: }
4034: return 0;
4035: }
4037: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4038: {
4039: PetscInt f, g;
4041: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4042: for (f = 0; f < rows; ++f) {
4043: PetscPrintf(PETSC_COMM_SELF, " |");
4044: for (g = 0; g < cols; ++g) {
4045: PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4046: }
4047: PetscPrintf(PETSC_COMM_SELF, " |\n");
4048: }
4049: return 0;
4050: }
4052: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4053: {
4054: PetscInt localSize, bs;
4055: PetscMPIInt size;
4056: Vec x, xglob;
4057: const PetscScalar *xarray;
4059: MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4060: VecDuplicate(X, &x);
4061: VecCopy(X, x);
4062: VecChop(x, tol);
4063: PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4064: if (size > 1) {
4065: VecGetLocalSize(x,&localSize);
4066: VecGetArrayRead(x,&xarray);
4067: VecGetBlockSize(x,&bs);
4068: VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4069: } else {
4070: xglob = x;
4071: }
4072: VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4073: if (size > 1) {
4074: VecDestroy(&xglob);
4075: VecRestoreArrayRead(x,&xarray);
4076: }
4077: VecDestroy(&x);
4078: return 0;
4079: }
4081: /*@
4082: DMGetSection - Get the PetscSection encoding the local data layout for the DM. This is equivalent to DMGetLocalSection(). Deprecated in v3.12
4084: Input Parameter:
4085: . dm - The DM
4087: Output Parameter:
4088: . section - The PetscSection
4090: Options Database Keys:
4091: . -dm_petscsection_view - View the Section created by the DM
4093: Level: advanced
4095: Notes:
4096: Use DMGetLocalSection() in new code.
4098: This gets a borrowed reference, so the user should not destroy this PetscSection.
4100: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4101: @*/
4102: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4103: {
4104: DMGetLocalSection(dm,section);
4105: return 0;
4106: }
4108: /*@
4109: DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
4111: Input Parameter:
4112: . dm - The DM
4114: Output Parameter:
4115: . section - The PetscSection
4117: Options Database Keys:
4118: . -dm_petscsection_view - View the Section created by the DM
4120: Level: intermediate
4122: Note: 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: (*dm->ops->createlocalsection)(dm);
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 Section 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: Any existing Section will be destroyed
4191: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4192: @*/
4193: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4194: {
4195: PetscInt numFields = 0;
4196: PetscInt f;
4200: PetscObjectReference((PetscObject)section);
4201: PetscSectionDestroy(&dm->localSection);
4202: dm->localSection = section;
4203: if (section) PetscSectionGetNumFields(dm->localSection, &numFields);
4204: if (numFields) {
4205: DMSetNumFields(dm, numFields);
4206: for (f = 0; f < numFields; ++f) {
4207: PetscObject disc;
4208: const char *name;
4210: PetscSectionGetFieldName(dm->localSection, f, &name);
4211: DMGetField(dm, f, NULL, &disc);
4212: PetscObjectSetName(disc, name);
4213: }
4214: }
4215: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4216: PetscSectionDestroy(&dm->globalSection);
4217: return 0;
4218: }
4220: /*@
4221: DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4223: not collective
4225: Input Parameter:
4226: . dm - The DM
4228: Output Parameters:
4229: + 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.
4230: . 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.
4231: - bias - Vector containing bias to be added to constrained dofs
4233: Level: advanced
4235: Note: This gets borrowed references, so the user should not destroy the PetscSection, Mat, or Vec.
4237: .seealso: DMSetDefaultConstraints()
4238: @*/
4239: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4240: {
4242: if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) (*dm->ops->createdefaultconstraints)(dm);
4243: if (section) *section = dm->defaultConstraint.section;
4244: if (mat) *mat = dm->defaultConstraint.mat;
4245: if (bias) *bias = dm->defaultConstraint.bias;
4246: return 0;
4247: }
4249: /*@
4250: DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4252: 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().
4254: 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.
4256: collective on dm
4258: Input Parameters:
4259: + dm - The DM
4260: . 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).
4261: . 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).
4262: - 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).
4264: Level: advanced
4266: Note: This increments the references of the PetscSection, Mat, and Vec, so they user can destroy them.
4268: .seealso: DMGetDefaultConstraints()
4269: @*/
4270: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4271: {
4272: PetscMPIInt result;
4275: if (section) {
4277: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4279: }
4280: if (mat) {
4282: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4284: }
4285: if (bias) {
4287: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)bias),&result);
4289: }
4290: PetscObjectReference((PetscObject)section);
4291: PetscSectionDestroy(&dm->defaultConstraint.section);
4292: dm->defaultConstraint.section = section;
4293: PetscObjectReference((PetscObject)mat);
4294: MatDestroy(&dm->defaultConstraint.mat);
4295: dm->defaultConstraint.mat = mat;
4296: PetscObjectReference((PetscObject)bias);
4297: VecDestroy(&dm->defaultConstraint.bias);
4298: dm->defaultConstraint.bias = bias;
4299: return 0;
4300: }
4302: #if defined(PETSC_USE_DEBUG)
4303: /*
4304: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4306: Input Parameters:
4307: + dm - The DM
4308: . localSection - PetscSection describing the local data layout
4309: - globalSection - PetscSection describing the global data layout
4311: Level: intermediate
4313: .seealso: DMGetSectionSF(), DMSetSectionSF()
4314: */
4315: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4316: {
4317: MPI_Comm comm;
4318: PetscLayout layout;
4319: const PetscInt *ranges;
4320: PetscInt pStart, pEnd, p, nroots;
4321: PetscMPIInt size, rank;
4322: PetscBool valid = PETSC_TRUE, gvalid;
4324: PetscObjectGetComm((PetscObject)dm,&comm);
4326: MPI_Comm_size(comm, &size);
4327: MPI_Comm_rank(comm, &rank);
4328: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4329: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4330: PetscLayoutCreate(comm, &layout);
4331: PetscLayoutSetBlockSize(layout, 1);
4332: PetscLayoutSetLocalSize(layout, nroots);
4333: PetscLayoutSetUp(layout);
4334: PetscLayoutGetRanges(layout, &ranges);
4335: for (p = pStart; p < pEnd; ++p) {
4336: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4338: PetscSectionGetDof(localSection, p, &dof);
4339: PetscSectionGetOffset(localSection, p, &off);
4340: PetscSectionGetConstraintDof(localSection, p, &cdof);
4341: PetscSectionGetDof(globalSection, p, &gdof);
4342: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4343: PetscSectionGetOffset(globalSection, p, &goff);
4344: if (!gdof) continue; /* Censored point */
4345: if ((gdof < 0 ? -(gdof+1) : gdof) != dof) {PetscSynchronizedPrintf(comm, "[%d]Global dof %d for point %d not equal to local dof %d\n", rank, gdof, p, dof); valid = PETSC_FALSE;}
4346: if (gcdof && (gcdof != cdof)) {PetscSynchronizedPrintf(comm, "[%d]Global constraints %d for point %d not equal to local constraints %d\n", rank, gcdof, p, cdof); valid = PETSC_FALSE;}
4347: if (gdof < 0) {
4348: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4349: for (d = 0; d < gsize; ++d) {
4350: PetscInt offset = -(goff+1) + d, r;
4352: PetscFindInt(offset,size+1,ranges,&r);
4353: if (r < 0) r = -(r+2);
4354: if ((r < 0) || (r >= size)) {PetscSynchronizedPrintf(comm, "[%d]Point %d mapped to invalid process %d (%d, %d)\n", rank, p, r, gdof, goff); valid = PETSC_FALSE;break;}
4355: }
4356: }
4357: }
4358: PetscLayoutDestroy(&layout);
4359: PetscSynchronizedFlush(comm, NULL);
4360: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4361: if (!gvalid) {
4362: DMView(dm, NULL);
4363: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4364: }
4365: return 0;
4366: }
4367: #endif
4369: /*@
4370: DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4372: Collective on dm
4374: Input Parameter:
4375: . dm - The DM
4377: Output Parameter:
4378: . section - The PetscSection
4380: Level: intermediate
4382: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4384: .seealso: DMSetLocalSection(), DMGetLocalSection()
4385: @*/
4386: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4387: {
4390: if (!dm->globalSection) {
4391: PetscSection s;
4393: DMGetLocalSection(dm, &s);
4396: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4397: PetscLayoutDestroy(&dm->map);
4398: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4399: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4400: }
4401: *section = dm->globalSection;
4402: return 0;
4403: }
4405: /*@
4406: DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4408: Input Parameters:
4409: + dm - The DM
4410: - section - The PetscSection, or NULL
4412: Level: intermediate
4414: Note: Any existing Section will be destroyed
4416: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4417: @*/
4418: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4419: {
4422: PetscObjectReference((PetscObject)section);
4423: PetscSectionDestroy(&dm->globalSection);
4424: dm->globalSection = section;
4425: #if defined(PETSC_USE_DEBUG)
4426: if (section) DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);
4427: #endif
4428: return 0;
4429: }
4431: /*@
4432: DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4433: it is created from the default PetscSection layouts in the DM.
4435: Input Parameter:
4436: . dm - The DM
4438: Output Parameter:
4439: . sf - The PetscSF
4441: Level: intermediate
4443: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4445: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4446: @*/
4447: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4448: {
4449: PetscInt nroots;
4453: if (!dm->sectionSF) {
4454: PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4455: }
4456: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4457: if (nroots < 0) {
4458: PetscSection section, gSection;
4460: DMGetLocalSection(dm, §ion);
4461: if (section) {
4462: DMGetGlobalSection(dm, &gSection);
4463: DMCreateSectionSF(dm, section, gSection);
4464: } else {
4465: *sf = NULL;
4466: return 0;
4467: }
4468: }
4469: *sf = dm->sectionSF;
4470: return 0;
4471: }
4473: /*@
4474: DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4476: Input Parameters:
4477: + dm - The DM
4478: - sf - The PetscSF
4480: Level: intermediate
4482: Note: Any previous SF is destroyed
4484: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4485: @*/
4486: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4487: {
4490: PetscObjectReference((PetscObject) sf);
4491: PetscSFDestroy(&dm->sectionSF);
4492: dm->sectionSF = sf;
4493: return 0;
4494: }
4496: /*@C
4497: DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4498: describing the data layout.
4500: Input Parameters:
4501: + dm - The DM
4502: . localSection - PetscSection describing the local data layout
4503: - globalSection - PetscSection describing the global data layout
4505: Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4507: Level: developer
4509: Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4510: directly into the DM, perhaps this function should not take the local and global sections as
4511: input and should just obtain them from the DM?
4513: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4514: @*/
4515: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4516: {
4518: PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4519: return 0;
4520: }
4522: /*@
4523: DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4525: Input Parameter:
4526: . dm - The DM
4528: Output Parameter:
4529: . sf - The PetscSF
4531: Level: intermediate
4533: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4535: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4536: @*/
4537: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4538: {
4541: *sf = dm->sf;
4542: return 0;
4543: }
4545: /*@
4546: DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4548: Input Parameters:
4549: + dm - The DM
4550: - sf - The PetscSF
4552: Level: intermediate
4554: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4555: @*/
4556: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4557: {
4560: PetscObjectReference((PetscObject) sf);
4561: PetscSFDestroy(&dm->sf);
4562: dm->sf = sf;
4563: return 0;
4564: }
4566: /*@
4567: DMGetNaturalSF - Get the PetscSF encoding the map back to the original mesh ordering
4569: Input Parameter:
4570: . dm - The DM
4572: Output Parameter:
4573: . sf - The PetscSF
4575: Level: intermediate
4577: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4579: .seealso: DMSetNaturalSF(), DMSetUseNatural(), DMGetUseNatural(), DMPlexCreateGlobalToNaturalSF(), DMPlexDistribute()
4580: @*/
4581: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4582: {
4585: *sf = dm->sfNatural;
4586: return 0;
4587: }
4589: /*@
4590: DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4592: Input Parameters:
4593: + dm - The DM
4594: - sf - The PetscSF
4596: Level: intermediate
4598: .seealso: DMGetNaturalSF(), DMSetUseNatural(), DMGetUseNatural(), DMPlexCreateGlobalToNaturalSF(), DMPlexDistribute()
4599: @*/
4600: PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4601: {
4604: PetscObjectReference((PetscObject) sf);
4605: PetscSFDestroy(&dm->sfNatural);
4606: dm->sfNatural = sf;
4607: return 0;
4608: }
4610: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4611: {
4612: PetscClassId id;
4614: PetscObjectGetClassId(disc, &id);
4615: if (id == PETSCFE_CLASSID) {
4616: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4617: } else if (id == PETSCFV_CLASSID) {
4618: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4619: } else {
4620: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4621: }
4622: return 0;
4623: }
4625: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4626: {
4627: RegionField *tmpr;
4628: PetscInt Nf = dm->Nf, f;
4630: if (Nf >= NfNew) return 0;
4631: PetscMalloc1(NfNew, &tmpr);
4632: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4633: for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4634: PetscFree(dm->fields);
4635: dm->Nf = NfNew;
4636: dm->fields = tmpr;
4637: return 0;
4638: }
4640: /*@
4641: DMClearFields - Remove all fields from the DM
4643: Logically collective on dm
4645: Input Parameter:
4646: . dm - The DM
4648: Level: intermediate
4650: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4651: @*/
4652: PetscErrorCode DMClearFields(DM dm)
4653: {
4654: PetscInt f;
4657: for (f = 0; f < dm->Nf; ++f) {
4658: PetscObjectDestroy(&dm->fields[f].disc);
4659: DMLabelDestroy(&dm->fields[f].label);
4660: }
4661: PetscFree(dm->fields);
4662: dm->fields = NULL;
4663: dm->Nf = 0;
4664: return 0;
4665: }
4667: /*@
4668: DMGetNumFields - Get the number of fields in the DM
4670: Not collective
4672: Input Parameter:
4673: . dm - The DM
4675: Output Parameter:
4676: . Nf - The number of fields
4678: Level: intermediate
4680: .seealso: DMSetNumFields(), DMSetField()
4681: @*/
4682: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4683: {
4686: *numFields = dm->Nf;
4687: return 0;
4688: }
4690: /*@
4691: DMSetNumFields - Set the number of fields in the DM
4693: Logically collective on dm
4695: Input Parameters:
4696: + dm - The DM
4697: - Nf - The number of fields
4699: Level: intermediate
4701: .seealso: DMGetNumFields(), DMSetField()
4702: @*/
4703: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4704: {
4705: PetscInt Nf, f;
4708: DMGetNumFields(dm, &Nf);
4709: for (f = Nf; f < numFields; ++f) {
4710: PetscContainer obj;
4712: PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4713: DMAddField(dm, NULL, (PetscObject) obj);
4714: PetscContainerDestroy(&obj);
4715: }
4716: return 0;
4717: }
4719: /*@
4720: DMGetField - Return the discretization object for a given DM field
4722: Not collective
4724: Input Parameters:
4725: + dm - The DM
4726: - f - The field number
4728: Output Parameters:
4729: + label - The label indicating the support of the field, or NULL for the entire mesh
4730: - field - The discretization object
4732: Level: intermediate
4734: .seealso: DMAddField(), DMSetField()
4735: @*/
4736: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4737: {
4741: if (label) *label = dm->fields[f].label;
4742: if (field) *field = dm->fields[f].disc;
4743: return 0;
4744: }
4746: /* Does not clear the DS */
4747: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4748: {
4749: DMFieldEnlarge_Static(dm, f+1);
4750: DMLabelDestroy(&dm->fields[f].label);
4751: PetscObjectDestroy(&dm->fields[f].disc);
4752: dm->fields[f].label = label;
4753: dm->fields[f].disc = field;
4754: PetscObjectReference((PetscObject) label);
4755: PetscObjectReference((PetscObject) field);
4756: return 0;
4757: }
4759: /*@
4760: DMSetField - Set the discretization object for a given DM field
4762: Logically collective on dm
4764: Input Parameters:
4765: + dm - The DM
4766: . f - The field number
4767: . label - The label indicating the support of the field, or NULL for the entire mesh
4768: - field - The discretization object
4770: Level: intermediate
4772: .seealso: DMAddField(), DMGetField()
4773: @*/
4774: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4775: {
4780: DMSetField_Internal(dm, f, label, field);
4781: DMSetDefaultAdjacency_Private(dm, f, field);
4782: DMClearDS(dm);
4783: return 0;
4784: }
4786: /*@
4787: DMAddField - Add the discretization object for the given DM field
4789: Logically collective on dm
4791: Input Parameters:
4792: + dm - The DM
4793: . label - The label indicating the support of the field, or NULL for the entire mesh
4794: - field - The discretization object
4796: Level: intermediate
4798: .seealso: DMSetField(), DMGetField()
4799: @*/
4800: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4801: {
4802: PetscInt Nf = dm->Nf;
4807: DMFieldEnlarge_Static(dm, Nf+1);
4808: dm->fields[Nf].label = label;
4809: dm->fields[Nf].disc = field;
4810: PetscObjectReference((PetscObject) label);
4811: PetscObjectReference((PetscObject) field);
4812: DMSetDefaultAdjacency_Private(dm, Nf, field);
4813: DMClearDS(dm);
4814: return 0;
4815: }
4817: /*@
4818: DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4820: Logically collective on dm
4822: Input Parameters:
4823: + dm - The DM
4824: . f - The field index
4825: - avoidTensor - The flag to avoid defining the field on tensor cells
4827: Level: intermediate
4829: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4830: @*/
4831: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4832: {
4834: dm->fields[f].avoidTensor = avoidTensor;
4835: return 0;
4836: }
4838: /*@
4839: DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4841: Logically collective on dm
4843: Input Parameters:
4844: + dm - The DM
4845: - f - The field index
4847: Output Parameter:
4848: . avoidTensor - The flag to avoid defining the field on tensor cells
4850: Level: intermediate
4852: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4853: @*/
4854: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4855: {
4857: *avoidTensor = dm->fields[f].avoidTensor;
4858: return 0;
4859: }
4861: /*@
4862: DMCopyFields - Copy the discretizations for the DM into another DM
4864: Collective on dm
4866: Input Parameter:
4867: . dm - The DM
4869: Output Parameter:
4870: . newdm - The DM
4872: Level: advanced
4874: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4875: @*/
4876: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4877: {
4878: PetscInt Nf, f;
4880: if (dm == newdm) return 0;
4881: DMGetNumFields(dm, &Nf);
4882: DMClearFields(newdm);
4883: for (f = 0; f < Nf; ++f) {
4884: DMLabel label;
4885: PetscObject field;
4886: PetscBool useCone, useClosure;
4888: DMGetField(dm, f, &label, &field);
4889: DMSetField(newdm, f, label, field);
4890: DMGetAdjacency(dm, f, &useCone, &useClosure);
4891: DMSetAdjacency(newdm, f, useCone, useClosure);
4892: }
4893: return 0;
4894: }
4896: /*@
4897: DMGetAdjacency - Returns the flags for determining variable influence
4899: Not collective
4901: Input Parameters:
4902: + dm - The DM object
4903: - f - The field number, or PETSC_DEFAULT for the default adjacency
4905: Output Parameters:
4906: + useCone - Flag for variable influence starting with the cone operation
4907: - useClosure - Flag for variable influence using transitive closure
4909: Notes:
4910: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4911: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4912: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4913: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4915: Level: developer
4917: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4918: @*/
4919: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4920: {
4924: if (f < 0) {
4925: if (useCone) *useCone = dm->adjacency[0];
4926: if (useClosure) *useClosure = dm->adjacency[1];
4927: } else {
4928: PetscInt Nf;
4930: DMGetNumFields(dm, &Nf);
4932: if (useCone) *useCone = dm->fields[f].adjacency[0];
4933: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4934: }
4935: return 0;
4936: }
4938: /*@
4939: DMSetAdjacency - Set the flags for determining variable influence
4941: Not collective
4943: Input Parameters:
4944: + dm - The DM object
4945: . f - The field number
4946: . useCone - Flag for variable influence starting with the cone operation
4947: - useClosure - Flag for variable influence using transitive closure
4949: Notes:
4950: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4951: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4952: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4953: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4955: Level: developer
4957: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4958: @*/
4959: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4960: {
4962: if (f < 0) {
4963: dm->adjacency[0] = useCone;
4964: dm->adjacency[1] = useClosure;
4965: } else {
4966: PetscInt Nf;
4968: DMGetNumFields(dm, &Nf);
4970: dm->fields[f].adjacency[0] = useCone;
4971: dm->fields[f].adjacency[1] = useClosure;
4972: }
4973: return 0;
4974: }
4976: /*@
4977: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4979: Not collective
4981: Input Parameter:
4982: . dm - The DM object
4984: Output Parameters:
4985: + useCone - Flag for variable influence starting with the cone operation
4986: - useClosure - Flag for variable influence using transitive closure
4988: Notes:
4989: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4990: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4991: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4993: Level: developer
4995: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4996: @*/
4997: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4998: {
4999: PetscInt Nf;
5004: DMGetNumFields(dm, &Nf);
5005: if (!Nf) {
5006: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5007: } else {
5008: DMGetAdjacency(dm, 0, useCone, useClosure);
5009: }
5010: return 0;
5011: }
5013: /*@
5014: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5016: Not collective
5018: Input Parameters:
5019: + dm - The DM object
5020: . useCone - Flag for variable influence starting with the cone operation
5021: - useClosure - Flag for variable influence using transitive closure
5023: Notes:
5024: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5025: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5026: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5028: Level: developer
5030: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5031: @*/
5032: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5033: {
5034: PetscInt Nf;
5037: DMGetNumFields(dm, &Nf);
5038: if (!Nf) {
5039: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5040: } else {
5041: DMSetAdjacency(dm, 0, useCone, useClosure);
5042: }
5043: return 0;
5044: }
5046: /* Complete labels that are being used for FEM BC */
5047: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
5048: {
5049: PetscObject obj;
5050: PetscClassId id;
5051: PetscInt Nbd, bd;
5052: PetscBool isFE = PETSC_FALSE;
5053: PetscBool duplicate = PETSC_FALSE;
5055: DMGetField(dm, field, NULL, &obj);
5056: PetscObjectGetClassId(obj, &id);
5057: if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5058: if (isFE && label) {
5059: /* Only want to modify label once */
5060: PetscDSGetNumBoundary(ds, &Nbd);
5061: for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5062: DMLabel l;
5064: PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5065: duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
5066: if (duplicate) break;
5067: }
5068: if (!duplicate) {
5069: DM plex;
5071: DMConvert(dm, DMPLEX, &plex);
5072: if (plex) DMPlexLabelComplete(plex, label);
5073: DMDestroy(&plex);
5074: }
5075: }
5076: return 0;
5077: }
5079: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5080: {
5081: DMSpace *tmpd;
5082: PetscInt Nds = dm->Nds, s;
5084: if (Nds >= NdsNew) return 0;
5085: PetscMalloc1(NdsNew, &tmpd);
5086: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5087: for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5088: PetscFree(dm->probs);
5089: dm->Nds = NdsNew;
5090: dm->probs = tmpd;
5091: return 0;
5092: }
5094: /*@
5095: DMGetNumDS - Get the number of discrete systems in the DM
5097: Not collective
5099: Input Parameter:
5100: . dm - The DM
5102: Output Parameter:
5103: . Nds - The number of PetscDS objects
5105: Level: intermediate
5107: .seealso: DMGetDS(), DMGetCellDS()
5108: @*/
5109: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5110: {
5113: *Nds = dm->Nds;
5114: return 0;
5115: }
5117: /*@
5118: DMClearDS - Remove all discrete systems from the DM
5120: Logically collective on dm
5122: Input Parameter:
5123: . dm - The DM
5125: Level: intermediate
5127: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5128: @*/
5129: PetscErrorCode DMClearDS(DM dm)
5130: {
5131: PetscInt s;
5134: for (s = 0; s < dm->Nds; ++s) {
5135: PetscDSDestroy(&dm->probs[s].ds);
5136: DMLabelDestroy(&dm->probs[s].label);
5137: ISDestroy(&dm->probs[s].fields);
5138: }
5139: PetscFree(dm->probs);
5140: dm->probs = NULL;
5141: dm->Nds = 0;
5142: return 0;
5143: }
5145: /*@
5146: DMGetDS - Get the default PetscDS
5148: Not collective
5150: Input Parameter:
5151: . dm - The DM
5153: Output Parameter:
5154: . prob - The default PetscDS
5156: Level: intermediate
5158: .seealso: DMGetCellDS(), DMGetRegionDS()
5159: @*/
5160: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5161: {
5165: if (dm->Nds <= 0) {
5166: PetscDS ds;
5168: PetscDSCreate(PETSC_COMM_SELF, &ds);
5169: DMSetRegionDS(dm, NULL, NULL, ds);
5170: PetscDSDestroy(&ds);
5171: }
5172: *prob = dm->probs[0].ds;
5173: return 0;
5174: }
5176: /*@
5177: DMGetCellDS - Get the PetscDS defined on a given cell
5179: Not collective
5181: Input Parameters:
5182: + dm - The DM
5183: - point - Cell for the DS
5185: Output Parameter:
5186: . prob - The PetscDS defined on the given cell
5188: Level: developer
5190: .seealso: DMGetDS(), DMSetRegionDS()
5191: @*/
5192: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5193: {
5194: PetscDS probDef = NULL;
5195: PetscInt s;
5201: *prob = NULL;
5202: for (s = 0; s < dm->Nds; ++s) {
5203: PetscInt val;
5205: if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5206: else {
5207: DMLabelGetValue(dm->probs[s].label, point, &val);
5208: if (val >= 0) {*prob = dm->probs[s].ds; break;}
5209: }
5210: }
5211: if (!*prob) *prob = probDef;
5212: return 0;
5213: }
5215: /*@
5216: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5218: Not collective
5220: Input Parameters:
5221: + dm - The DM
5222: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5224: Output Parameters:
5225: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5226: - prob - The PetscDS defined on the given region, or NULL
5228: Note:
5229: If a non-NULL label is given, but there is no PetscDS on that specific label,
5230: the PetscDS for the full domain (if present) is returned. Returns with
5231: fields=NULL and prob=NULL if there is no PetscDS for the full domain.
5233: Level: advanced
5235: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5236: @*/
5237: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5238: {
5239: PetscInt Nds = dm->Nds, s;
5245: for (s = 0; s < Nds; ++s) {
5246: if (dm->probs[s].label == label || !dm->probs[s].label) {
5247: if (fields) *fields = dm->probs[s].fields;
5248: if (ds) *ds = dm->probs[s].ds;
5249: if (dm->probs[s].label) return 0;
5250: }
5251: }
5252: return 0;
5253: }
5255: /*@
5256: DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5258: Collective on dm
5260: Input Parameters:
5261: + dm - The DM
5262: . label - The DMLabel defining the mesh region, or NULL for the entire mesh
5263: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5264: - prob - The PetscDS defined on the given cell
5266: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5267: the fields argument is ignored.
5269: Level: advanced
5271: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5272: @*/
5273: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5274: {
5275: PetscInt Nds = dm->Nds, s;
5280: for (s = 0; s < Nds; ++s) {
5281: if (dm->probs[s].label == label) {
5282: PetscDSDestroy(&dm->probs[s].ds);
5283: dm->probs[s].ds = ds;
5284: return 0;
5285: }
5286: }
5287: DMDSEnlarge_Static(dm, Nds+1);
5288: PetscObjectReference((PetscObject) label);
5289: PetscObjectReference((PetscObject) fields);
5290: PetscObjectReference((PetscObject) ds);
5291: if (!label) {
5292: /* Put the NULL label at the front, so it is returned as the default */
5293: for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5294: Nds = 0;
5295: }
5296: dm->probs[Nds].label = label;
5297: dm->probs[Nds].fields = fields;
5298: dm->probs[Nds].ds = ds;
5299: return 0;
5300: }
5302: /*@
5303: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5305: Not collective
5307: Input Parameters:
5308: + dm - The DM
5309: - num - The region number, in [0, Nds)
5311: Output Parameters:
5312: + label - The region label, or NULL
5313: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5314: - ds - The PetscDS defined on the given region, or NULL
5316: Level: advanced
5318: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5319: @*/
5320: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5321: {
5322: PetscInt Nds;
5325: DMGetNumDS(dm, &Nds);
5327: if (label) {
5329: *label = dm->probs[num].label;
5330: }
5331: if (fields) {
5333: *fields = dm->probs[num].fields;
5334: }
5335: if (ds) {
5337: *ds = dm->probs[num].ds;
5338: }
5339: return 0;
5340: }
5342: /*@
5343: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5345: Not collective
5347: Input Parameters:
5348: + dm - The DM
5349: . num - The region number, in [0, Nds)
5350: . label - The region label, or NULL
5351: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5352: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5354: Level: advanced
5356: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5357: @*/
5358: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5359: {
5360: PetscInt Nds;
5364: DMGetNumDS(dm, &Nds);
5366: PetscObjectReference((PetscObject) label);
5367: DMLabelDestroy(&dm->probs[num].label);
5368: dm->probs[num].label = label;
5369: if (fields) {
5371: PetscObjectReference((PetscObject) fields);
5372: ISDestroy(&dm->probs[num].fields);
5373: dm->probs[num].fields = fields;
5374: }
5375: if (ds) {
5377: PetscObjectReference((PetscObject) ds);
5378: PetscDSDestroy(&dm->probs[num].ds);
5379: dm->probs[num].ds = ds;
5380: }
5381: return 0;
5382: }
5384: /*@
5385: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5387: Not collective
5389: Input Parameters:
5390: + dm - The DM
5391: - ds - The PetscDS defined on the given region
5393: Output Parameter:
5394: . num - The region number, in [0, Nds), or -1 if not found
5396: Level: advanced
5398: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5399: @*/
5400: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5401: {
5402: PetscInt Nds, n;
5407: DMGetNumDS(dm, &Nds);
5408: for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5409: if (n >= Nds) *num = -1;
5410: else *num = n;
5411: return 0;
5412: }
5414: /*@C
5415: DMCreateFEDefault - Create a PetscFE based on the celltype for the mesh
5417: Not collective
5419: Input Parameters:
5420: + dm - The DM
5421: . Nc - The number of components for the field
5422: . prefix - The options prefix for the output PetscFE, or NULL
5423: - qorder - The quadrature order or PETSC_DETERMINE to use PetscSpace polynomial degree
5425: Output Parameter:
5426: . fem - The PetscFE
5428: Note: This is a convenience method that just calls PetscFECreateByCell() underneath.
5430: Level: intermediate
5432: .seealso: PetscFECreateByCell(), DMAddField(), DMCreateDS(), DMGetCellDS(), DMGetRegionDS()
5433: @*/
5434: PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5435: {
5436: DMPolytopeType ct;
5437: PetscInt dim, cStart;
5444: DMGetDimension(dm, &dim);
5445: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5446: DMPlexGetCellType(dm, cStart, &ct);
5447: PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem);
5448: return 0;
5449: }
5451: /*@
5452: DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5454: Collective on dm
5456: Input Parameter:
5457: . dm - The DM
5459: Options Database Keys:
5460: . -dm_petscds_view - View all the PetscDS objects in this DM
5462: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5464: Level: intermediate
5466: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5467: @*/
5468: PetscErrorCode DMCreateDS(DM dm)
5469: {
5470: MPI_Comm comm;
5471: PetscDS dsDef;
5472: DMLabel *labelSet;
5473: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5474: PetscBool doSetup = PETSC_TRUE, flg;
5477: if (!dm->fields) return 0;
5478: PetscObjectGetComm((PetscObject) dm, &comm);
5479: DMGetCoordinateDim(dm, &dE);
5480: /* Determine how many regions we have */
5481: PetscMalloc1(Nf, &labelSet);
5482: Nl = 0;
5483: Ndef = 0;
5484: for (f = 0; f < Nf; ++f) {
5485: DMLabel label = dm->fields[f].label;
5486: PetscInt l;
5488: #ifdef PETSC_HAVE_LIBCEED
5489: /* Move CEED context to discretizations */
5490: {
5491: PetscClassId id;
5493: PetscObjectGetClassId(dm->fields[f].disc, &id);
5494: if (id == PETSCFE_CLASSID) {
5495: Ceed ceed;
5497: DMGetCeed(dm, &ceed);
5498: PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
5499: }
5500: }
5501: #endif
5502: if (!label) {++Ndef; continue;}
5503: for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5504: if (l < Nl) continue;
5505: labelSet[Nl++] = label;
5506: }
5507: /* Create default DS if there are no labels to intersect with */
5508: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5509: if (!dsDef && Ndef && !Nl) {
5510: IS fields;
5511: PetscInt *fld, nf;
5513: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5515: PetscMalloc1(nf, &fld);
5516: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5517: ISCreate(PETSC_COMM_SELF, &fields);
5518: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5519: ISSetType(fields, ISGENERAL);
5520: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5522: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5523: DMSetRegionDS(dm, NULL, fields, dsDef);
5524: PetscDSDestroy(&dsDef);
5525: ISDestroy(&fields);
5526: }
5527: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5528: if (dsDef) PetscDSSetCoordinateDimension(dsDef, dE);
5529: /* Intersect labels with default fields */
5530: if (Ndef && Nl) {
5531: DM plex;
5532: DMLabel cellLabel;
5533: IS fieldIS, allcellIS, defcellIS = NULL;
5534: PetscInt *fields;
5535: const PetscInt *cells;
5536: PetscInt depth, nf = 0, n, c;
5538: DMConvert(dm, DMPLEX, &plex);
5539: DMPlexGetDepth(plex, &depth);
5540: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5541: if (!allcellIS) DMGetStratumIS(plex, "depth", depth, &allcellIS);
5542: /* TODO This looks like it only works for one label */
5543: for (l = 0; l < Nl; ++l) {
5544: DMLabel label = labelSet[l];
5545: IS pointIS;
5547: ISDestroy(&defcellIS);
5548: DMLabelGetStratumIS(label, 1, &pointIS);
5549: ISDifference(allcellIS, pointIS, &defcellIS);
5550: ISDestroy(&pointIS);
5551: }
5552: ISDestroy(&allcellIS);
5554: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5555: ISGetLocalSize(defcellIS, &n);
5556: ISGetIndices(defcellIS, &cells);
5557: for (c = 0; c < n; ++c) DMLabelSetValue(cellLabel, cells[c], 1);
5558: ISRestoreIndices(defcellIS, &cells);
5559: ISDestroy(&defcellIS);
5560: DMPlexLabelComplete(plex, cellLabel);
5562: PetscMalloc1(Ndef, &fields);
5563: for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5564: ISCreate(PETSC_COMM_SELF, &fieldIS);
5565: PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5566: ISSetType(fieldIS, ISGENERAL);
5567: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5569: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5570: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5571: PetscDSSetCoordinateDimension(dsDef, dE);
5572: DMLabelDestroy(&cellLabel);
5573: PetscDSDestroy(&dsDef);
5574: ISDestroy(&fieldIS);
5575: DMDestroy(&plex);
5576: }
5577: /* Create label DSes
5578: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5579: */
5580: /* TODO Should check that labels are disjoint */
5581: for (l = 0; l < Nl; ++l) {
5582: DMLabel label = labelSet[l];
5583: PetscDS ds;
5584: IS fields;
5585: PetscInt *fld, nf;
5587: PetscDSCreate(PETSC_COMM_SELF, &ds);
5588: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5589: PetscMalloc1(nf, &fld);
5590: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5591: ISCreate(PETSC_COMM_SELF, &fields);
5592: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5593: ISSetType(fields, ISGENERAL);
5594: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5595: DMSetRegionDS(dm, label, fields, ds);
5596: ISDestroy(&fields);
5597: PetscDSSetCoordinateDimension(ds, dE);
5598: {
5599: DMPolytopeType ct;
5600: PetscInt lStart, lEnd;
5601: PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive;
5603: DMLabelGetBounds(label, &lStart, &lEnd);
5604: if (lStart >= 0) {
5605: DMPlexGetCellType(dm, lStart, &ct);
5606: switch (ct) {
5607: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5608: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5609: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5610: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5611: isCohesiveLocal = PETSC_TRUE;break;
5612: default: break;
5613: }
5614: }
5615: MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm);
5616: for (f = 0, nf = 0; f < Nf; ++f) {
5617: if (label == dm->fields[f].label || !dm->fields[f].label) {
5618: if (label == dm->fields[f].label) {
5619: PetscDSSetDiscretization(ds, nf, NULL);
5620: PetscDSSetCohesive(ds, nf, isCohesive);
5621: }
5622: ++nf;
5623: }
5624: }
5625: }
5626: PetscDSDestroy(&ds);
5627: }
5628: PetscFree(labelSet);
5629: /* Set fields in DSes */
5630: for (s = 0; s < dm->Nds; ++s) {
5631: PetscDS ds = dm->probs[s].ds;
5632: IS fields = dm->probs[s].fields;
5633: const PetscInt *fld;
5634: PetscInt nf, dsnf;
5635: PetscBool isCohesive;
5637: PetscDSGetNumFields(ds, &dsnf);
5638: PetscDSIsCohesive(ds, &isCohesive);
5639: ISGetLocalSize(fields, &nf);
5640: ISGetIndices(fields, &fld);
5641: for (f = 0; f < nf; ++f) {
5642: PetscObject disc = dm->fields[fld[f]].disc;
5643: PetscBool isCohesiveField;
5644: PetscClassId id;
5646: /* Handle DS with no fields */
5647: if (dsnf) PetscDSGetCohesive(ds, f, &isCohesiveField);
5648: /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5649: if (isCohesive && !isCohesiveField) PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);
5650: PetscDSSetDiscretization(ds, f, disc);
5651: /* We allow people to have placeholder fields and construct the Section by hand */
5652: PetscObjectGetClassId(disc, &id);
5653: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5654: }
5655: ISRestoreIndices(fields, &fld);
5656: }
5657: /* Allow k-jet tabulation */
5658: PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5659: if (flg) {
5660: for (s = 0; s < dm->Nds; ++s) {
5661: PetscDS ds = dm->probs[s].ds;
5662: PetscInt Nf, f;
5664: PetscDSGetNumFields(ds, &Nf);
5665: for (f = 0; f < Nf; ++f) PetscDSSetJetDegree(ds, f, k);
5666: }
5667: }
5668: /* Setup DSes */
5669: if (doSetup) {
5670: for (s = 0; s < dm->Nds; ++s) PetscDSSetUp(dm->probs[s].ds);
5671: }
5672: return 0;
5673: }
5675: /*@
5676: DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5678: Collective on DM
5680: Input Parameters:
5681: + dm - The DM
5682: - time - The time
5684: Output Parameters:
5685: + u - The vector will be filled with exact solution values, or NULL
5686: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5688: Note: The user must call PetscDSSetExactSolution() beforehand
5690: Level: developer
5692: .seealso: PetscDSSetExactSolution()
5693: @*/
5694: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5695: {
5696: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5697: void **ectxs;
5698: PetscInt Nf, Nds, s;
5703: DMGetNumFields(dm, &Nf);
5704: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5705: DMGetNumDS(dm, &Nds);
5706: for (s = 0; s < Nds; ++s) {
5707: PetscDS ds;
5708: DMLabel label;
5709: IS fieldIS;
5710: const PetscInt *fields, id = 1;
5711: PetscInt dsNf, f;
5713: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5714: PetscDSGetNumFields(ds, &dsNf);
5715: ISGetIndices(fieldIS, &fields);
5716: PetscArrayzero(exacts, Nf);
5717: PetscArrayzero(ectxs, Nf);
5718: if (u) {
5719: for (f = 0; f < dsNf; ++f) {
5720: const PetscInt field = fields[f];
5721: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5722: }
5723: ISRestoreIndices(fieldIS, &fields);
5724: if (label) {
5725: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5726: } else {
5727: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5728: }
5729: }
5730: if (u_t) {
5731: PetscArrayzero(exacts, Nf);
5732: PetscArrayzero(ectxs, Nf);
5733: for (f = 0; f < dsNf; ++f) {
5734: const PetscInt field = fields[f];
5735: PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5736: }
5737: ISRestoreIndices(fieldIS, &fields);
5738: if (label) {
5739: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5740: } else {
5741: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5742: }
5743: }
5744: }
5745: if (u) {
5746: PetscObjectSetName((PetscObject) u, "Exact Solution");
5747: PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5748: }
5749: if (u_t) {
5750: PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5751: PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5752: }
5753: PetscFree2(exacts, ectxs);
5754: return 0;
5755: }
5757: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5758: {
5759: PetscDS dsNew;
5760: DSBoundary b;
5761: PetscInt cdim, Nf, f;
5762: PetscBool isCohesive;
5763: void *ctx;
5765: PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5766: PetscDSCopyConstants(ds, dsNew);
5767: PetscDSCopyExactSolutions(ds, dsNew);
5768: PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5769: PetscDSCopyEquations(ds, dsNew);
5770: PetscDSGetNumFields(ds, &Nf);
5771: for (f = 0; f < Nf; ++f) {
5772: PetscDSGetContext(ds, f, &ctx);
5773: PetscDSSetContext(dsNew, f, ctx);
5774: PetscDSGetCohesive(ds, f, &isCohesive);
5775: PetscDSSetCohesive(dsNew, f, isCohesive);
5776: }
5777: if (Nf) {
5778: PetscDSGetCoordinateDimension(ds, &cdim);
5779: PetscDSSetCoordinateDimension(dsNew, cdim);
5780: }
5781: PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5782: for (b = dsNew->boundary; b; b = b->next) {
5783: DMGetLabel(dm, b->lname, &b->label);
5784: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5786: }
5788: DMSetRegionDS(dm, label, fields, dsNew);
5789: PetscDSDestroy(&dsNew);
5790: return 0;
5791: }
5793: /*@
5794: DMCopyDS - Copy the discrete systems for the DM into another DM
5796: Collective on dm
5798: Input Parameter:
5799: . dm - The DM
5801: Output Parameter:
5802: . newdm - The DM
5804: Level: advanced
5806: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5807: @*/
5808: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5809: {
5810: PetscInt Nds, s;
5812: if (dm == newdm) return 0;
5813: DMGetNumDS(dm, &Nds);
5814: DMClearDS(newdm);
5815: for (s = 0; s < Nds; ++s) {
5816: DMLabel label;
5817: IS fields;
5818: PetscDS ds, newds;
5819: PetscInt Nbd, bd;
5821: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5822: /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5823: DMTransferDS_Internal(newdm, label, fields, ds);
5824: /* Commplete new labels in the new DS */
5825: DMGetRegionDS(newdm, label, NULL, &newds);
5826: PetscDSGetNumBoundary(newds, &Nbd);
5827: for (bd = 0; bd < Nbd; ++bd) {
5828: PetscWeakForm wf;
5829: DMLabel label;
5830: PetscInt field;
5832: PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5833: DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5834: PetscWeakFormReplaceLabel(wf, label);
5835: }
5836: }
5837: return 0;
5838: }
5840: /*@
5841: DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5843: Collective on dm
5845: Input Parameter:
5846: . dm - The DM
5848: Output Parameter:
5849: . newdm - The DM
5851: Level: advanced
5853: .seealso: DMCopyFields(), DMCopyDS()
5854: @*/
5855: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5856: {
5857: DMCopyFields(dm, newdm);
5858: DMCopyDS(dm, newdm);
5859: return 0;
5860: }
5862: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5863: {
5864: DM dm_coord,dmc_coord;
5865: Vec coords,ccoords;
5866: Mat inject;
5867: DMGetCoordinateDM(dm,&dm_coord);
5868: DMGetCoordinateDM(dmc,&dmc_coord);
5869: DMGetCoordinates(dm,&coords);
5870: DMGetCoordinates(dmc,&ccoords);
5871: if (coords && !ccoords) {
5872: DMCreateGlobalVector(dmc_coord,&ccoords);
5873: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5874: DMCreateInjection(dmc_coord,dm_coord,&inject);
5875: MatRestrict(inject,coords,ccoords);
5876: MatDestroy(&inject);
5877: DMSetCoordinates(dmc,ccoords);
5878: VecDestroy(&ccoords);
5879: }
5880: return 0;
5881: }
5883: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5884: {
5885: DM dm_coord,subdm_coord;
5886: Vec coords,ccoords,clcoords;
5887: VecScatter *scat_i,*scat_g;
5888: DMGetCoordinateDM(dm,&dm_coord);
5889: DMGetCoordinateDM(subdm,&subdm_coord);
5890: DMGetCoordinates(dm,&coords);
5891: DMGetCoordinates(subdm,&ccoords);
5892: if (coords && !ccoords) {
5893: DMCreateGlobalVector(subdm_coord,&ccoords);
5894: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5895: DMCreateLocalVector(subdm_coord,&clcoords);
5896: PetscObjectSetName((PetscObject)clcoords,"coordinates");
5897: DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5898: VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5899: VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5900: VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5901: VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5902: DMSetCoordinates(subdm,ccoords);
5903: DMSetCoordinatesLocal(subdm,clcoords);
5904: VecScatterDestroy(&scat_i[0]);
5905: VecScatterDestroy(&scat_g[0]);
5906: VecDestroy(&ccoords);
5907: VecDestroy(&clcoords);
5908: PetscFree(scat_i);
5909: PetscFree(scat_g);
5910: }
5911: return 0;
5912: }
5914: /*@
5915: DMGetDimension - Return the topological dimension of the DM
5917: Not collective
5919: Input Parameter:
5920: . dm - The DM
5922: Output Parameter:
5923: . dim - The topological dimension
5925: Level: beginner
5927: .seealso: DMSetDimension(), DMCreate()
5928: @*/
5929: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5930: {
5933: *dim = dm->dim;
5934: return 0;
5935: }
5937: /*@
5938: DMSetDimension - Set the topological dimension of the DM
5940: Collective on dm
5942: Input Parameters:
5943: + dm - The DM
5944: - dim - The topological dimension
5946: Level: beginner
5948: .seealso: DMGetDimension(), DMCreate()
5949: @*/
5950: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5951: {
5952: PetscDS ds;
5953: PetscInt Nds, n;
5957: dm->dim = dim;
5958: if (dm->dim >= 0) {
5959: DMGetNumDS(dm, &Nds);
5960: for (n = 0; n < Nds; ++n) {
5961: DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
5962: if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
5963: }
5964: }
5965: return 0;
5966: }
5968: /*@
5969: DMGetDimPoints - Get the half-open interval for all points of a given dimension
5971: Collective on dm
5973: Input Parameters:
5974: + dm - the DM
5975: - dim - the dimension
5977: Output Parameters:
5978: + pStart - The first point of the given dimension
5979: - pEnd - The first point following points of the given dimension
5981: Note:
5982: The points are vertices in the Hasse diagram encoding the topology. This is explained in
5983: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5984: then the interval is empty.
5986: Level: intermediate
5988: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5989: @*/
5990: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5991: {
5992: PetscInt d;
5995: DMGetDimension(dm, &d);
5998: (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5999: return 0;
6000: }
6002: /*@
6003: DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
6005: Collective on dm
6007: Input Parameters:
6008: + dm - the DM
6009: - c - coordinate vector
6011: Notes:
6012: The coordinates do include those for ghost points, which are in the local vector.
6014: The vector c should be destroyed by the caller.
6016: Level: intermediate
6018: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6019: @*/
6020: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6021: {
6024: PetscObjectReference((PetscObject) c);
6025: VecDestroy(&dm->coordinates);
6026: dm->coordinates = c;
6027: VecDestroy(&dm->coordinatesLocal);
6028: DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6029: DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6030: return 0;
6031: }
6033: /*@
6034: DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
6036: Not collective
6038: Input Parameters:
6039: + dm - the DM
6040: - c - coordinate vector
6042: Notes:
6043: The coordinates of ghost points can be set using DMSetCoordinates()
6044: followed by DMGetCoordinatesLocal(). This is intended to enable the
6045: setting of ghost coordinates outside of the domain.
6047: The vector c should be destroyed by the caller.
6049: Level: intermediate
6051: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6052: @*/
6053: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6054: {
6057: PetscObjectReference((PetscObject) c);
6058: VecDestroy(&dm->coordinatesLocal);
6060: dm->coordinatesLocal = c;
6062: VecDestroy(&dm->coordinates);
6063: return 0;
6064: }
6066: /*@
6067: DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
6069: Collective on dm
6071: Input Parameter:
6072: . dm - the DM
6074: Output Parameter:
6075: . c - global coordinate vector
6077: Note:
6078: This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6079: destroyed the array will no longer be valid.
6081: Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).
6083: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6084: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6086: Level: intermediate
6088: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6089: @*/
6090: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6091: {
6094: if (!dm->coordinates && dm->coordinatesLocal) {
6095: DM cdm = NULL;
6096: PetscBool localized;
6098: DMGetCoordinateDM(dm, &cdm);
6099: DMCreateGlobalVector(cdm, &dm->coordinates);
6100: DMGetCoordinatesLocalized(dm, &localized);
6101: /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6102: if (localized) {
6103: PetscInt cdim;
6105: DMGetCoordinateDim(dm, &cdim);
6106: VecSetBlockSize(dm->coordinates, cdim);
6107: }
6108: PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6109: DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6110: DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6111: }
6112: *c = dm->coordinates;
6113: return 0;
6114: }
6116: /*@
6117: DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6119: Collective on dm
6121: Input Parameter:
6122: . dm - the DM
6124: Level: advanced
6126: .seealso: DMGetCoordinatesLocalNoncollective()
6127: @*/
6128: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6129: {
6131: if (!dm->coordinatesLocal && dm->coordinates) {
6132: DM cdm = NULL;
6133: PetscBool localized;
6135: DMGetCoordinateDM(dm, &cdm);
6136: DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6137: DMGetCoordinatesLocalized(dm, &localized);
6138: /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6139: if (localized) {
6140: PetscInt cdim;
6142: DMGetCoordinateDim(dm, &cdim);
6143: VecSetBlockSize(dm->coordinates, cdim);
6144: }
6145: PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6146: DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6147: DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6148: }
6149: return 0;
6150: }
6152: /*@
6153: DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6155: Collective on dm
6157: Input Parameter:
6158: . dm - the DM
6160: Output Parameter:
6161: . c - coordinate vector
6163: Note:
6164: This is a borrowed reference, so the user should NOT destroy this vector
6166: Each process has the local and ghost coordinates
6168: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6169: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6171: Level: intermediate
6173: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6174: @*/
6175: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6176: {
6179: DMGetCoordinatesLocalSetUp(dm);
6180: *c = dm->coordinatesLocal;
6181: return 0;
6182: }
6184: /*@
6185: DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6187: Not collective
6189: Input Parameter:
6190: . dm - the DM
6192: Output Parameter:
6193: . c - coordinate vector
6195: Level: advanced
6197: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6198: @*/
6199: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6200: {
6204: *c = dm->coordinatesLocal;
6205: return 0;
6206: }
6208: /*@
6209: DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6211: Not collective
6213: Input Parameters:
6214: + dm - the DM
6215: - p - the IS of points whose coordinates will be returned
6217: Output Parameters:
6218: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6219: - pCoord - the Vec with coordinates of points in p
6221: Note:
6222: DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6224: This creates a new vector, so the user SHOULD destroy this vector
6226: Each process has the local and ghost coordinates
6228: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6229: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6231: Level: advanced
6233: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6234: @*/
6235: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6236: {
6237: PetscSection cs, newcs;
6238: Vec coords;
6239: const PetscScalar *arr;
6240: PetscScalar *newarr=NULL;
6241: PetscInt n;
6249: cs = dm->coordinateDM->localSection;
6250: coords = dm->coordinatesLocal;
6251: VecGetArrayRead(coords, &arr);
6252: PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6253: VecRestoreArrayRead(coords, &arr);
6254: if (pCoord) {
6255: PetscSectionGetStorageSize(newcs, &n);
6256: /* set array in two steps to mimic PETSC_OWN_POINTER */
6257: VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6258: VecReplaceArray(*pCoord, newarr);
6259: } else {
6260: PetscFree(newarr);
6261: }
6262: if (pCoordSection) {*pCoordSection = newcs;}
6263: else PetscSectionDestroy(&newcs);
6264: return 0;
6265: }
6267: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6268: {
6271: if (!dm->coordinateField) {
6272: if (dm->ops->createcoordinatefield) {
6273: (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6274: }
6275: }
6276: *field = dm->coordinateField;
6277: return 0;
6278: }
6280: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6281: {
6284: PetscObjectReference((PetscObject)field);
6285: DMFieldDestroy(&dm->coordinateField);
6286: dm->coordinateField = field;
6287: return 0;
6288: }
6290: /*@
6291: DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6293: Collective on dm
6295: Input Parameter:
6296: . dm - the DM
6298: Output Parameter:
6299: . cdm - coordinate DM
6301: Level: intermediate
6303: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6304: @*/
6305: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6306: {
6309: if (!dm->coordinateDM) {
6310: DM cdm;
6313: (*dm->ops->createcoordinatedm)(dm, &cdm);
6314: PetscObjectSetName((PetscObject)cdm, "coordinateDM");
6315: /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6316: * until the call to CreateCoordinateDM) */
6317: DMDestroy(&dm->coordinateDM);
6318: dm->coordinateDM = cdm;
6319: }
6320: *cdm = dm->coordinateDM;
6321: return 0;
6322: }
6324: /*@
6325: DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6327: Logically Collective on dm
6329: Input Parameters:
6330: + dm - the DM
6331: - cdm - coordinate DM
6333: Level: intermediate
6335: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6336: @*/
6337: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6338: {
6341: PetscObjectReference((PetscObject)cdm);
6342: DMDestroy(&dm->coordinateDM);
6343: dm->coordinateDM = cdm;
6344: return 0;
6345: }
6347: /*@
6348: DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6350: Not Collective
6352: Input Parameter:
6353: . dm - The DM object
6355: Output Parameter:
6356: . dim - The embedding dimension
6358: Level: intermediate
6360: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6361: @*/
6362: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6363: {
6366: if (dm->dimEmbed == PETSC_DEFAULT) {
6367: dm->dimEmbed = dm->dim;
6368: }
6369: *dim = dm->dimEmbed;
6370: return 0;
6371: }
6373: /*@
6374: DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6376: Not Collective
6378: Input Parameters:
6379: + dm - The DM object
6380: - dim - The embedding dimension
6382: Level: intermediate
6384: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6385: @*/
6386: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6387: {
6388: PetscDS ds;
6389: PetscInt Nds, n;
6392: dm->dimEmbed = dim;
6393: if (dm->dim >= 0) {
6394: DMGetNumDS(dm, &Nds);
6395: for (n = 0; n < Nds; ++n) {
6396: DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6397: PetscDSSetCoordinateDimension(ds, dim);
6398: }
6399: }
6400: return 0;
6401: }
6403: /*@
6404: DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6406: Collective on dm
6408: Input Parameter:
6409: . dm - The DM object
6411: Output Parameter:
6412: . section - The PetscSection object
6414: Level: intermediate
6416: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6417: @*/
6418: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6419: {
6420: DM cdm;
6424: DMGetCoordinateDM(dm, &cdm);
6425: DMGetLocalSection(cdm, section);
6426: return 0;
6427: }
6429: /*@
6430: DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6432: Not Collective
6434: Input Parameters:
6435: + dm - The DM object
6436: . dim - The embedding dimension, or PETSC_DETERMINE
6437: - section - The PetscSection object
6439: Level: intermediate
6441: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6442: @*/
6443: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6444: {
6445: DM cdm;
6449: DMGetCoordinateDM(dm, &cdm);
6450: DMSetLocalSection(cdm, section);
6451: if (dim == PETSC_DETERMINE) {
6452: PetscInt d = PETSC_DEFAULT;
6453: PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6455: PetscSectionGetChart(section, &pStart, &pEnd);
6456: DMGetDimPoints(dm, 0, &vStart, &vEnd);
6457: pStart = PetscMax(vStart, pStart);
6458: pEnd = PetscMin(vEnd, pEnd);
6459: for (v = pStart; v < pEnd; ++v) {
6460: PetscSectionGetDof(section, v, &dd);
6461: if (dd) {d = dd; break;}
6462: }
6463: if (d >= 0) DMSetCoordinateDim(dm, d);
6464: }
6465: return 0;
6466: }
6468: /*@
6469: DMProjectCoordinates - Project coordinates to a different space
6471: Input Parameters:
6472: + dm - The DM object
6473: - disc - The new coordinate discretization or NULL to ensure a coordinate discretization exists
6475: Level: intermediate
6477: .seealso: DMGetCoordinateField()
6478: @*/
6479: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6480: {
6481: PetscFE discOld;
6482: PetscClassId classid;
6483: DM cdmOld,cdmNew;
6484: Vec coordsOld,coordsNew;
6485: Mat matInterp;
6486: PetscBool same_space = PETSC_TRUE;
6491: DMGetCoordinateDM(dm, &cdmOld);
6492: /* Check current discretization is compatible */
6493: DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
6494: PetscObjectGetClassId((PetscObject)discOld, &classid);
6495: if (classid != PETSCFE_CLASSID) {
6496: if (classid == PETSC_CONTAINER_CLASSID) {
6497: PetscFE feLinear;
6498: DMPolytopeType ct;
6499: PetscInt dim, dE, cStart, cEnd;
6500: PetscBool simplex;
6502: /* Assume linear vertex coordinates */
6503: DMGetDimension(dm, &dim);
6504: DMGetCoordinateDim(dm, &dE);
6505: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6506: if (cEnd > cStart) {
6507: DMPlexGetCellType(dm, cStart, &ct);
6508: switch (ct) {
6509: case DM_POLYTOPE_TRI_PRISM:
6510: case DM_POLYTOPE_TRI_PRISM_TENSOR:
6511: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6512: default: break;
6513: }
6514: }
6515: DMPlexIsSimplex(dm, &simplex);
6516: PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6517: DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6518: PetscFEDestroy(&feLinear);
6519: DMCreateDS(cdmOld);
6520: DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
6521: } else {
6522: const char *discname;
6524: PetscObjectGetType((PetscObject)discOld, &discname);
6525: SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6526: }
6527: }
6528: if (!disc) return 0;
6529: { // Check if the new space is the same as the old modulo quadrature
6530: PetscDualSpace dsOld, ds;
6531: PetscFEGetDualSpace(discOld, &dsOld);
6532: PetscFEGetDualSpace(disc, &ds);
6533: PetscDualSpaceEqual(dsOld, ds, &same_space);
6534: }
6535: /* Make a fresh clone of the coordinate DM */
6536: DMClone(cdmOld, &cdmNew);
6537: DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6538: DMCreateDS(cdmNew);
6539: DMGetCoordinates(dm, &coordsOld);
6540: if (same_space) {
6541: PetscObjectReference((PetscObject)coordsOld);
6542: coordsNew = coordsOld;
6543: } else { // Project the coordinate vector from old to new space
6544: DMCreateGlobalVector(cdmNew, &coordsNew);
6545: DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6546: MatInterpolate(matInterp, coordsOld, coordsNew);
6547: MatDestroy(&matInterp);
6548: }
6549: /* Set new coordinate structures */
6550: DMSetCoordinateField(dm, NULL);
6551: DMSetCoordinateDM(dm, cdmNew);
6552: DMSetCoordinates(dm, coordsNew);
6553: VecDestroy(&coordsNew);
6554: DMDestroy(&cdmNew);
6555: return 0;
6556: }
6558: /*@C
6559: DMGetPeriodicity - Get the description of mesh periodicity
6561: Input Parameter:
6562: . dm - The DM object
6564: Output Parameters:
6565: + per - Whether the DM is periodic or not
6566: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6567: . L - If we assume the mesh is a torus, this is the length of each coordinate
6568: - bd - This describes the type of periodicity in each topological dimension
6570: Level: developer
6572: .seealso: DMGetPeriodicity()
6573: @*/
6574: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6575: {
6577: if (per) *per = dm->periodic;
6578: if (L) *L = dm->L;
6579: if (maxCell) *maxCell = dm->maxCell;
6580: if (bd) *bd = dm->bdtype;
6581: return 0;
6582: }
6584: /*@C
6585: DMSetPeriodicity - Set the description of mesh periodicity
6587: Input Parameters:
6588: + dm - The DM object
6589: . per - Whether the DM is periodic or not.
6590: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
6591: . L - If we assume the mesh is a torus, this is the length of each coordinate
6592: - bd - This describes the type of periodicity in each topological dimension
6594: Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.
6596: Level: developer
6598: .seealso: DMGetPeriodicity()
6599: @*/
6600: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6601: {
6602: PetscInt dim, d;
6609: DMGetDimension(dm, &dim);
6610: if (maxCell) {
6611: if (!dm->maxCell) PetscMalloc1(dim, &dm->maxCell);
6612: for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6613: } else { /* remove maxCell information to disable automatic computation of localized vertices */
6614: PetscFree(dm->maxCell);
6615: }
6617: if (L) {
6618: if (!dm->L) PetscMalloc1(dim, &dm->L);
6619: for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6620: }
6621: if (bd) {
6622: if (!dm->bdtype) PetscMalloc1(dim, &dm->bdtype);
6623: for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6624: }
6625: dm->periodic = per;
6626: return 0;
6627: }
6629: /*@
6630: DMLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension.
6632: Input Parameters:
6633: + dm - The DM
6634: . in - The input coordinate point (dim numbers)
6635: - endpoint - Include the endpoint L_i
6637: Output Parameter:
6638: . out - The localized coordinate point
6640: Level: developer
6642: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6643: @*/
6644: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6645: {
6646: PetscInt dim, d;
6648: DMGetCoordinateDim(dm, &dim);
6649: if (!dm->maxCell) {
6650: for (d = 0; d < dim; ++d) out[d] = in[d];
6651: } else {
6652: if (endpoint) {
6653: for (d = 0; d < dim; ++d) {
6654: if ((PetscAbsReal(PetscRealPart(in[d])/dm->L[d] - PetscFloorReal(PetscRealPart(in[d])/dm->L[d])) < PETSC_SMALL) && (PetscRealPart(in[d])/dm->L[d] > PETSC_SMALL)) {
6655: out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6656: } else {
6657: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6658: }
6659: }
6660: } else {
6661: for (d = 0; d < dim; ++d) {
6662: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6663: }
6664: }
6665: }
6666: return 0;
6667: }
6669: /*
6670: DMLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.
6672: Input Parameters:
6673: + dm - The DM
6674: . dim - The spatial dimension
6675: . anchor - The anchor point, the input point can be no more than maxCell away from it
6676: - in - The input coordinate point (dim numbers)
6678: Output Parameter:
6679: . out - The localized coordinate point
6681: Level: developer
6683: Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell
6685: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6686: */
6687: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6688: {
6689: PetscInt d;
6691: if (!dm->maxCell) {
6692: for (d = 0; d < dim; ++d) out[d] = in[d];
6693: } else {
6694: for (d = 0; d < dim; ++d) {
6695: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6696: out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6697: } else {
6698: out[d] = in[d];
6699: }
6700: }
6701: }
6702: return 0;
6703: }
6705: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6706: {
6707: PetscInt d;
6709: if (!dm->maxCell) {
6710: for (d = 0; d < dim; ++d) out[d] = in[d];
6711: } else {
6712: for (d = 0; d < dim; ++d) {
6713: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6714: out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6715: } else {
6716: out[d] = in[d];
6717: }
6718: }
6719: }
6720: return 0;
6721: }
6723: /*
6724: DMLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.
6726: Input Parameters:
6727: + dm - The DM
6728: . dim - The spatial dimension
6729: . anchor - The anchor point, the input point can be no more than maxCell away from it
6730: . in - The input coordinate delta (dim numbers)
6731: - out - The input coordinate point (dim numbers)
6733: Output Parameter:
6734: . out - The localized coordinate in + out
6736: Level: developer
6738: Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell
6740: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6741: */
6742: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6743: {
6744: PetscInt d;
6746: if (!dm->maxCell) {
6747: for (d = 0; d < dim; ++d) out[d] += in[d];
6748: } else {
6749: for (d = 0; d < dim; ++d) {
6750: const PetscReal maxC = dm->maxCell[d];
6752: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6753: const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6755: if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6756: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
6757: out[d] += newCoord;
6758: } else {
6759: out[d] += in[d];
6760: }
6761: }
6762: }
6763: return 0;
6764: }
6766: /*@
6767: DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6769: Not collective
6771: Input Parameter:
6772: . dm - The DM
6774: Output Parameter:
6775: areLocalized - True if localized
6777: Level: developer
6779: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6780: @*/
6781: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6782: {
6783: DM cdm;
6784: PetscSection coordSection;
6785: PetscInt depth, cStart, cEnd, sStart, sEnd, c, dof;
6786: PetscBool isPlex, alreadyLocalized;
6790: *areLocalized = PETSC_FALSE;
6792: /* We need some generic way of refering to cells/vertices */
6793: DMGetCoordinateDM(dm, &cdm);
6794: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6795: if (!isPlex) return 0;
6796: DMPlexGetDepth(cdm, &depth);
6797: if (!depth) return 0;
6799: DMGetCoordinateSection(dm, &coordSection);
6800: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6801: PetscSectionGetChart(coordSection, &sStart, &sEnd);
6802: alreadyLocalized = PETSC_FALSE;
6803: for (c = cStart; c < cEnd; ++c) {
6804: if (c < sStart || c >= sEnd) continue;
6805: PetscSectionGetDof(coordSection, c, &dof);
6806: if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6807: }
6808: *areLocalized = alreadyLocalized;
6809: return 0;
6810: }
6812: /*@
6813: DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6815: Collective on dm
6817: Input Parameter:
6818: . dm - The DM
6820: Output Parameter:
6821: areLocalized - True if localized
6823: Level: developer
6825: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6826: @*/
6827: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6828: {
6829: PetscBool localized;
6833: DMGetCoordinatesLocalizedLocal(dm,&localized);
6834: MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6835: return 0;
6836: }
6838: /*@
6839: DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6841: Collective on dm
6843: Input Parameter:
6844: . dm - The DM
6846: Level: developer
6848: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6849: @*/
6850: PetscErrorCode DMLocalizeCoordinates(DM dm)
6851: {
6852: DM cdm;
6853: PetscSection coordSection, cSection;
6854: Vec coordinates, cVec;
6855: PetscScalar *coords, *coords2, *anchor, *localized;
6856: PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6857: PetscBool alreadyLocalized, alreadyLocalizedGlobal;
6858: PetscInt maxHeight = 0, h;
6859: PetscInt *pStart = NULL, *pEnd = NULL;
6862: if (!dm->periodic) return 0;
6863: DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6864: if (alreadyLocalized) return 0;
6866: /* We need some generic way of refering to cells/vertices */
6867: DMGetCoordinateDM(dm, &cdm);
6868: {
6869: PetscBool isplex;
6871: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6872: if (isplex) {
6873: DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6874: DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6875: DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6876: pEnd = &pStart[maxHeight + 1];
6877: newStart = vStart;
6878: newEnd = vEnd;
6879: for (h = 0; h <= maxHeight; h++) {
6880: DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6881: newStart = PetscMin(newStart,pStart[h]);
6882: newEnd = PetscMax(newEnd,pEnd[h]);
6883: }
6884: } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6885: }
6886: DMGetCoordinatesLocal(dm, &coordinates);
6888: DMGetCoordinateSection(dm, &coordSection);
6889: VecGetBlockSize(coordinates, &bs);
6890: PetscSectionGetChart(coordSection,&sStart,&sEnd);
6892: PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6893: PetscSectionSetNumFields(cSection, 1);
6894: PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6895: PetscSectionSetFieldComponents(cSection, 0, Nc);
6896: PetscSectionSetChart(cSection, newStart, newEnd);
6898: DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6899: localized = &anchor[bs];
6900: alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6901: for (h = 0; h <= maxHeight; h++) {
6902: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6904: for (c = cStart; c < cEnd; ++c) {
6905: PetscScalar *cellCoords = NULL;
6906: PetscInt b;
6908: if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6909: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6910: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6911: for (d = 0; d < dof/bs; ++d) {
6912: DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6913: for (b = 0; b < bs; b++) {
6914: if (cellCoords[d*bs + b] != localized[b]) break;
6915: }
6916: if (b < bs) break;
6917: }
6918: if (d < dof/bs) {
6919: if (c >= sStart && c < sEnd) {
6920: PetscInt cdof;
6922: PetscSectionGetDof(coordSection, c, &cdof);
6923: if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6924: }
6925: PetscSectionSetDof(cSection, c, dof);
6926: PetscSectionSetFieldDof(cSection, c, 0, dof);
6927: }
6928: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6929: }
6930: }
6931: MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6932: if (alreadyLocalizedGlobal) {
6933: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6934: PetscSectionDestroy(&cSection);
6935: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6936: return 0;
6937: }
6938: for (v = vStart; v < vEnd; ++v) {
6939: PetscSectionGetDof(coordSection, v, &dof);
6940: PetscSectionSetDof(cSection, v, dof);
6941: PetscSectionSetFieldDof(cSection, v, 0, dof);
6942: }
6943: PetscSectionSetUp(cSection);
6944: PetscSectionGetStorageSize(cSection, &coordSize);
6945: VecCreate(PETSC_COMM_SELF, &cVec);
6946: PetscObjectSetName((PetscObject)cVec,"coordinates");
6947: VecSetBlockSize(cVec, bs);
6948: VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6949: VecSetType(cVec, VECSTANDARD);
6950: VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6951: VecGetArray(cVec, &coords2);
6952: for (v = vStart; v < vEnd; ++v) {
6953: PetscSectionGetDof(coordSection, v, &dof);
6954: PetscSectionGetOffset(coordSection, v, &off);
6955: PetscSectionGetOffset(cSection, v, &off2);
6956: for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6957: }
6958: for (h = 0; h <= maxHeight; h++) {
6959: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6961: for (c = cStart; c < cEnd; ++c) {
6962: PetscScalar *cellCoords = NULL;
6963: PetscInt b, cdof;
6965: PetscSectionGetDof(cSection,c,&cdof);
6966: if (!cdof) continue;
6967: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6968: PetscSectionGetOffset(cSection, c, &off2);
6969: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6970: for (d = 0; d < dof/bs; ++d) DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);
6971: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6972: }
6973: }
6974: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6975: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6976: VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6977: VecRestoreArray(cVec, &coords2);
6978: DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6979: DMSetCoordinatesLocal(dm, cVec);
6980: VecDestroy(&cVec);
6981: PetscSectionDestroy(&cSection);
6982: return 0;
6983: }
6985: /*@
6986: DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6988: Collective on v (see explanation below)
6990: Input Parameters:
6991: + dm - The DM
6992: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6994: Input/Output Parameters:
6995: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6996: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
6997: on output, the PetscSF containing the ranks and local indices of the containing points
6999: Level: developer
7001: Notes:
7002: To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7003: To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
7005: If *cellSF is NULL on input, a PetscSF will be created.
7006: If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
7008: An array that maps each point to its containing cell can be obtained with
7010: $ const PetscSFNode *cells;
7011: $ PetscInt nFound;
7012: $ const PetscInt *found;
7013: $
7014: $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
7016: Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7017: the index of the cell in its rank's local numbering.
7019: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7020: @*/
7021: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7022: {
7026: if (*cellSF) {
7027: PetscMPIInt result;
7030: MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7032: } else {
7033: PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7034: }
7036: PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7037: (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7038: PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7039: return 0;
7040: }
7042: /*@
7043: DMGetOutputDM - Retrieve the DM associated with the layout for output
7045: Collective on dm
7047: Input Parameter:
7048: . dm - The original DM
7050: Output Parameter:
7051: . odm - The DM which provides the layout for output
7053: Level: intermediate
7055: .seealso: VecView(), DMGetGlobalSection()
7056: @*/
7057: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7058: {
7059: PetscSection section;
7060: PetscBool hasConstraints, ghasConstraints;
7064: DMGetLocalSection(dm, §ion);
7065: PetscSectionHasConstraints(section, &hasConstraints);
7066: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7067: if (!ghasConstraints) {
7068: *odm = dm;
7069: return 0;
7070: }
7071: if (!dm->dmBC) {
7072: PetscSection newSection, gsection;
7073: PetscSF sf;
7075: DMClone(dm, &dm->dmBC);
7076: DMCopyDisc(dm, dm->dmBC);
7077: PetscSectionClone(section, &newSection);
7078: DMSetLocalSection(dm->dmBC, newSection);
7079: PetscSectionDestroy(&newSection);
7080: DMGetPointSF(dm->dmBC, &sf);
7081: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7082: DMSetGlobalSection(dm->dmBC, gsection);
7083: PetscSectionDestroy(&gsection);
7084: }
7085: *odm = dm->dmBC;
7086: return 0;
7087: }
7089: /*@
7090: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7092: Input Parameter:
7093: . dm - The original DM
7095: Output Parameters:
7096: + num - The output sequence number
7097: - val - The output sequence value
7099: Level: intermediate
7101: Note: This is intended for output that should appear in sequence, for instance
7102: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7104: .seealso: VecView()
7105: @*/
7106: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7107: {
7111: return 0;
7112: }
7114: /*@
7115: DMSetOutputSequenceNumber - Set the sequence number/value for output
7117: Input Parameters:
7118: + dm - The original DM
7119: . num - The output sequence number
7120: - val - The output sequence value
7122: Level: intermediate
7124: Note: This is intended for output that should appear in sequence, for instance
7125: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7127: .seealso: VecView()
7128: @*/
7129: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7130: {
7132: dm->outputSequenceNum = num;
7133: dm->outputSequenceVal = val;
7134: return 0;
7135: }
7137: /*@C
7138: DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7140: Input Parameters:
7141: + dm - The original DM
7142: . name - The sequence name
7143: - num - The output sequence number
7145: Output Parameter:
7146: . val - The output sequence value
7148: Level: intermediate
7150: Note: This is intended for output that should appear in sequence, for instance
7151: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7153: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7154: @*/
7155: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7156: {
7157: PetscBool ishdf5;
7162: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7163: if (ishdf5) {
7164: #if defined(PETSC_HAVE_HDF5)
7165: PetscScalar value;
7167: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7168: *val = PetscRealPart(value);
7169: #endif
7170: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7171: return 0;
7172: }
7174: /*@
7175: DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7177: Not collective
7179: Input Parameter:
7180: . dm - The DM
7182: Output Parameter:
7183: . useNatural - The flag to build the mapping to a natural order during distribution
7185: Level: beginner
7187: .seealso: DMSetUseNatural(), DMCreate()
7188: @*/
7189: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7190: {
7193: *useNatural = dm->useNatural;
7194: return 0;
7195: }
7197: /*@
7198: DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7200: Collective on dm
7202: Input Parameters:
7203: + dm - The DM
7204: - useNatural - The flag to build the mapping to a natural order during distribution
7206: Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7208: Level: beginner
7210: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7211: @*/
7212: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7213: {
7216: dm->useNatural = useNatural;
7217: return 0;
7218: }
7220: /*@C
7221: DMCreateLabel - Create a label of the given name if it does not already exist
7223: Not Collective
7225: Input Parameters:
7226: + dm - The DM object
7227: - name - The label name
7229: Level: intermediate
7231: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7232: @*/
7233: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7234: {
7235: PetscBool flg;
7236: DMLabel label;
7240: DMHasLabel(dm, name, &flg);
7241: if (!flg) {
7242: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7243: DMAddLabel(dm, label);
7244: DMLabelDestroy(&label);
7245: }
7246: return 0;
7247: }
7249: /*@C
7250: DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists, move it to this index.
7252: Not Collective
7254: Input Parameters:
7255: + dm - The DM object
7256: . l - The index for the label
7257: - name - The label name
7259: Level: intermediate
7261: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7262: @*/
7263: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7264: {
7265: DMLabelLink orig, prev = NULL;
7266: DMLabel label;
7267: PetscInt Nl, m;
7268: PetscBool flg, match;
7269: const char *lname;
7273: DMHasLabel(dm, name, &flg);
7274: if (!flg) {
7275: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7276: DMAddLabel(dm, label);
7277: DMLabelDestroy(&label);
7278: }
7279: DMGetNumLabels(dm, &Nl);
7281: for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7282: PetscObjectGetName((PetscObject) orig->label, &lname);
7283: PetscStrcmp(name, lname, &match);
7284: if (match) break;
7285: }
7286: if (m == l) return 0;
7287: if (!m) dm->labels = orig->next;
7288: else prev->next = orig->next;
7289: if (!l) {
7290: orig->next = dm->labels;
7291: dm->labels = orig;
7292: } else {
7293: for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7294: orig->next = prev->next;
7295: prev->next = orig;
7296: }
7297: return 0;
7298: }
7300: /*@C
7301: DMGetLabelValue - Get the value in a DMLabel for the given point, with -1 as the default
7303: Not Collective
7305: Input Parameters:
7306: + dm - The DM object
7307: . name - The label name
7308: - point - The mesh point
7310: Output Parameter:
7311: . value - The label value for this point, or -1 if the point is not in the label
7313: Level: beginner
7315: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7316: @*/
7317: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7318: {
7319: DMLabel label;
7323: DMGetLabel(dm, name, &label);
7325: DMLabelGetValue(label, point, value);
7326: return 0;
7327: }
7329: /*@C
7330: DMSetLabelValue - Add a point to a DMLabel with given value
7332: Not Collective
7334: Input Parameters:
7335: + dm - The DM object
7336: . name - The label name
7337: . point - The mesh point
7338: - value - The label value for this point
7340: Output Parameter:
7342: Level: beginner
7344: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7345: @*/
7346: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7347: {
7348: DMLabel label;
7352: DMGetLabel(dm, name, &label);
7353: if (!label) {
7354: DMCreateLabel(dm, name);
7355: DMGetLabel(dm, name, &label);
7356: }
7357: DMLabelSetValue(label, point, value);
7358: return 0;
7359: }
7361: /*@C
7362: DMClearLabelValue - Remove a point from a DMLabel with given value
7364: Not Collective
7366: Input Parameters:
7367: + dm - The DM object
7368: . name - The label name
7369: . point - The mesh point
7370: - value - The label value for this point
7372: Output Parameter:
7374: Level: beginner
7376: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7377: @*/
7378: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7379: {
7380: DMLabel label;
7384: DMGetLabel(dm, name, &label);
7385: if (!label) return 0;
7386: DMLabelClearValue(label, point, value);
7387: return 0;
7388: }
7390: /*@C
7391: DMGetLabelSize - Get the number of different integer ids in a Label
7393: Not Collective
7395: Input Parameters:
7396: + dm - The DM object
7397: - name - The label name
7399: Output Parameter:
7400: . size - The number of different integer ids, or 0 if the label does not exist
7402: Level: beginner
7404: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7405: @*/
7406: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7407: {
7408: DMLabel label;
7413: DMGetLabel(dm, name, &label);
7414: *size = 0;
7415: if (!label) return 0;
7416: DMLabelGetNumValues(label, size);
7417: return 0;
7418: }
7420: /*@C
7421: DMGetLabelIdIS - Get the integer ids in a label
7423: Not Collective
7425: Input Parameters:
7426: + mesh - The DM object
7427: - name - The label name
7429: Output Parameter:
7430: . ids - The integer ids, or NULL if the label does not exist
7432: Level: beginner
7434: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7435: @*/
7436: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7437: {
7438: DMLabel label;
7443: DMGetLabel(dm, name, &label);
7444: *ids = NULL;
7445: if (label) {
7446: DMLabelGetValueIS(label, ids);
7447: } else {
7448: /* returning an empty IS */
7449: ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7450: }
7451: return 0;
7452: }
7454: /*@C
7455: DMGetStratumSize - Get the number of points in a label stratum
7457: Not Collective
7459: Input Parameters:
7460: + dm - The DM object
7461: . name - The label name
7462: - value - The stratum value
7464: Output Parameter:
7465: . size - The stratum size
7467: Level: beginner
7469: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7470: @*/
7471: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7472: {
7473: DMLabel label;
7478: DMGetLabel(dm, name, &label);
7479: *size = 0;
7480: if (!label) return 0;
7481: DMLabelGetStratumSize(label, value, size);
7482: return 0;
7483: }
7485: /*@C
7486: DMGetStratumIS - Get the points in a label stratum
7488: Not Collective
7490: Input Parameters:
7491: + dm - The DM object
7492: . name - The label name
7493: - value - The stratum value
7495: Output Parameter:
7496: . points - The stratum points, or NULL if the label does not exist or does not have that value
7498: Level: beginner
7500: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7501: @*/
7502: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7503: {
7504: DMLabel label;
7509: DMGetLabel(dm, name, &label);
7510: *points = NULL;
7511: if (!label) return 0;
7512: DMLabelGetStratumIS(label, value, points);
7513: return 0;
7514: }
7516: /*@C
7517: DMSetStratumIS - Set the points in a label stratum
7519: Not Collective
7521: Input Parameters:
7522: + dm - The DM object
7523: . name - The label name
7524: . value - The stratum value
7525: - points - The stratum points
7527: Level: beginner
7529: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7530: @*/
7531: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7532: {
7533: DMLabel label;
7538: DMGetLabel(dm, name, &label);
7539: if (!label) return 0;
7540: DMLabelSetStratumIS(label, value, points);
7541: return 0;
7542: }
7544: /*@C
7545: DMClearLabelStratum - Remove all points from a stratum from a DMLabel
7547: Not Collective
7549: Input Parameters:
7550: + dm - The DM object
7551: . name - The label name
7552: - value - The label value for this point
7554: Output Parameter:
7556: Level: beginner
7558: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7559: @*/
7560: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7561: {
7562: DMLabel label;
7566: DMGetLabel(dm, name, &label);
7567: if (!label) return 0;
7568: DMLabelClearStratum(label, value);
7569: return 0;
7570: }
7572: /*@
7573: DMGetNumLabels - Return the number of labels defined by the mesh
7575: Not Collective
7577: Input Parameter:
7578: . dm - The DM object
7580: Output Parameter:
7581: . numLabels - the number of Labels
7583: Level: intermediate
7585: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7586: @*/
7587: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7588: {
7589: DMLabelLink next = dm->labels;
7590: PetscInt n = 0;
7594: while (next) {++n; next = next->next;}
7595: *numLabels = n;
7596: return 0;
7597: }
7599: /*@C
7600: DMGetLabelName - Return the name of nth label
7602: Not Collective
7604: Input Parameters:
7605: + dm - The DM object
7606: - n - the label number
7608: Output Parameter:
7609: . name - the label name
7611: Level: intermediate
7613: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7614: @*/
7615: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7616: {
7617: DMLabelLink next = dm->labels;
7618: PetscInt l = 0;
7622: while (next) {
7623: if (l == n) {
7624: PetscObjectGetName((PetscObject) next->label, name);
7625: return 0;
7626: }
7627: ++l;
7628: next = next->next;
7629: }
7630: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7631: }
7633: /*@C
7634: DMHasLabel - Determine whether the mesh has a label of a given name
7636: Not Collective
7638: Input Parameters:
7639: + dm - The DM object
7640: - name - The label name
7642: Output Parameter:
7643: . hasLabel - PETSC_TRUE if the label is present
7645: Level: intermediate
7647: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7648: @*/
7649: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7650: {
7651: DMLabelLink next = dm->labels;
7652: const char *lname;
7657: *hasLabel = PETSC_FALSE;
7658: while (next) {
7659: PetscObjectGetName((PetscObject) next->label, &lname);
7660: PetscStrcmp(name, lname, hasLabel);
7661: if (*hasLabel) break;
7662: next = next->next;
7663: }
7664: return 0;
7665: }
7667: /*@C
7668: DMGetLabel - Return the label of a given name, or NULL
7670: Not Collective
7672: Input Parameters:
7673: + dm - The DM object
7674: - name - The label name
7676: Output Parameter:
7677: . label - The DMLabel, or NULL if the label is absent
7679: Note: Some of the default labels in a DMPlex will be
7680: $ "depth" - Holds the depth (co-dimension) of each mesh point
7681: $ "celltype" - Holds the topological type of each cell
7682: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7683: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7684: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7685: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7687: Level: intermediate
7689: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7690: @*/
7691: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7692: {
7693: DMLabelLink next = dm->labels;
7694: PetscBool hasLabel;
7695: const char *lname;
7700: *label = NULL;
7701: while (next) {
7702: PetscObjectGetName((PetscObject) next->label, &lname);
7703: PetscStrcmp(name, lname, &hasLabel);
7704: if (hasLabel) {
7705: *label = next->label;
7706: break;
7707: }
7708: next = next->next;
7709: }
7710: return 0;
7711: }
7713: /*@C
7714: DMGetLabelByNum - Return the nth label
7716: Not Collective
7718: Input Parameters:
7719: + dm - The DM object
7720: - n - the label number
7722: Output Parameter:
7723: . label - the label
7725: Level: intermediate
7727: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7728: @*/
7729: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7730: {
7731: DMLabelLink next = dm->labels;
7732: PetscInt l = 0;
7736: while (next) {
7737: if (l == n) {
7738: *label = next->label;
7739: return 0;
7740: }
7741: ++l;
7742: next = next->next;
7743: }
7744: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7745: }
7747: /*@C
7748: DMAddLabel - Add the label to this mesh
7750: Not Collective
7752: Input Parameters:
7753: + dm - The DM object
7754: - label - The DMLabel
7756: Level: developer
7758: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7759: @*/
7760: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7761: {
7762: DMLabelLink l, *p, tmpLabel;
7763: PetscBool hasLabel;
7764: const char *lname;
7765: PetscBool flg;
7768: PetscObjectGetName((PetscObject) label, &lname);
7769: DMHasLabel(dm, lname, &hasLabel);
7771: PetscCalloc1(1, &tmpLabel);
7772: tmpLabel->label = label;
7773: tmpLabel->output = PETSC_TRUE;
7774: for (p=&dm->labels; (l=*p); p=&l->next) {}
7775: *p = tmpLabel;
7776: PetscObjectReference((PetscObject)label);
7777: PetscStrcmp(lname, "depth", &flg);
7778: if (flg) dm->depthLabel = label;
7779: PetscStrcmp(lname, "celltype", &flg);
7780: if (flg) dm->celltypeLabel = label;
7781: return 0;
7782: }
7784: /*@C
7785: DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7787: Not Collective
7789: Input Parameters:
7790: + dm - The DM object
7791: - label - The DMLabel, having the same name, to substitute
7793: Note: Some of the default labels in a DMPlex will be
7794: $ "depth" - Holds the depth (co-dimension) of each mesh point
7795: $ "celltype" - Holds the topological type of each cell
7796: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7797: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7798: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7799: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7801: Level: intermediate
7803: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7804: @*/
7805: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7806: {
7807: DMLabelLink next = dm->labels;
7808: PetscBool hasLabel, flg;
7809: const char *name, *lname;
7813: PetscObjectGetName((PetscObject) label, &name);
7814: while (next) {
7815: PetscObjectGetName((PetscObject) next->label, &lname);
7816: PetscStrcmp(name, lname, &hasLabel);
7817: if (hasLabel) {
7818: PetscObjectReference((PetscObject) label);
7819: PetscStrcmp(lname, "depth", &flg);
7820: if (flg) dm->depthLabel = label;
7821: PetscStrcmp(lname, "celltype", &flg);
7822: if (flg) dm->celltypeLabel = label;
7823: DMLabelDestroy(&next->label);
7824: next->label = label;
7825: break;
7826: }
7827: next = next->next;
7828: }
7829: return 0;
7830: }
7832: /*@C
7833: DMRemoveLabel - Remove the label given by name from this mesh
7835: Not Collective
7837: Input Parameters:
7838: + dm - The DM object
7839: - name - The label name
7841: Output Parameter:
7842: . label - The DMLabel, or NULL if the label is absent
7844: Level: developer
7846: Notes:
7847: DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7848: DMLabelDestroy() on the label.
7850: DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7851: call DMLabelDestroy(). Instead, the label is returned and the user is
7852: responsible of calling DMLabelDestroy() at some point.
7854: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7855: @*/
7856: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7857: {
7858: DMLabelLink link, *pnext;
7859: PetscBool hasLabel;
7860: const char *lname;
7864: if (label) {
7866: *label = NULL;
7867: }
7868: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7869: PetscObjectGetName((PetscObject) link->label, &lname);
7870: PetscStrcmp(name, lname, &hasLabel);
7871: if (hasLabel) {
7872: *pnext = link->next; /* Remove from list */
7873: PetscStrcmp(name, "depth", &hasLabel);
7874: if (hasLabel) dm->depthLabel = NULL;
7875: PetscStrcmp(name, "celltype", &hasLabel);
7876: if (hasLabel) dm->celltypeLabel = NULL;
7877: if (label) *label = link->label;
7878: else DMLabelDestroy(&link->label);
7879: PetscFree(link);
7880: break;
7881: }
7882: }
7883: return 0;
7884: }
7886: /*@
7887: DMRemoveLabelBySelf - Remove the label from this mesh
7889: Not Collective
7891: Input Parameters:
7892: + dm - The DM object
7893: . label - The DMLabel to be removed from the DM
7894: - failNotFound - Should it fail if the label is not found in the DM?
7896: Level: developer
7898: Notes:
7899: Only exactly the same instance is removed if found, name match is ignored.
7900: If the DM has an exclusive reference to the label, it gets destroyed and
7901: *label nullified.
7903: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7904: @*/
7905: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7906: {
7907: DMLabelLink link, *pnext;
7908: PetscBool hasLabel = PETSC_FALSE;
7912: if (!*label && !failNotFound) return 0;
7915: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7916: if (*label == link->label) {
7917: hasLabel = PETSC_TRUE;
7918: *pnext = link->next; /* Remove from list */
7919: if (*label == dm->depthLabel) dm->depthLabel = NULL;
7920: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7921: if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7922: DMLabelDestroy(&link->label);
7923: PetscFree(link);
7924: break;
7925: }
7926: }
7928: return 0;
7929: }
7931: /*@C
7932: DMGetLabelOutput - Get the output flag for a given label
7934: Not Collective
7936: Input Parameters:
7937: + dm - The DM object
7938: - name - The label name
7940: Output Parameter:
7941: . output - The flag for output
7943: Level: developer
7945: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7946: @*/
7947: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7948: {
7949: DMLabelLink next = dm->labels;
7950: const char *lname;
7955: while (next) {
7956: PetscBool flg;
7958: PetscObjectGetName((PetscObject) next->label, &lname);
7959: PetscStrcmp(name, lname, &flg);
7960: if (flg) {*output = next->output; return 0;}
7961: next = next->next;
7962: }
7963: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7964: }
7966: /*@C
7967: DMSetLabelOutput - Set the output flag for a given label
7969: Not Collective
7971: Input Parameters:
7972: + dm - The DM object
7973: . name - The label name
7974: - output - The flag for output
7976: Level: developer
7978: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7979: @*/
7980: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7981: {
7982: DMLabelLink next = dm->labels;
7983: const char *lname;
7987: while (next) {
7988: PetscBool flg;
7990: PetscObjectGetName((PetscObject) next->label, &lname);
7991: PetscStrcmp(name, lname, &flg);
7992: if (flg) {next->output = output; return 0;}
7993: next = next->next;
7994: }
7995: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7996: }
7998: /*@
7999: DMCopyLabels - Copy labels from one mesh to another with a superset of the points
8001: Collective on dmA
8003: Input Parameters:
8004: + dmA - The DM object with initial labels
8005: . dmB - The DM object to which labels are copied
8006: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8007: . all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8008: - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode)
8010: Level: intermediate
8012: Notes:
8013: This is typically used when interpolating or otherwise adding to a mesh, or testing.
8015: .seealso: DMAddLabel(), DMCopyLabelsMode
8016: @*/
8017: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
8018: {
8019: DMLabel label, labelNew, labelOld;
8020: const char *name;
8021: PetscBool flg;
8022: DMLabelLink link;
8029: if (dmA == dmB) return 0;
8030: for (link=dmA->labels; link; link=link->next) {
8031: label=link->label;
8032: PetscObjectGetName((PetscObject)label, &name);
8033: if (!all) {
8034: PetscStrcmp(name, "depth", &flg);
8035: if (flg) continue;
8036: PetscStrcmp(name, "dim", &flg);
8037: if (flg) continue;
8038: PetscStrcmp(name, "celltype", &flg);
8039: if (flg) continue;
8040: }
8041: DMGetLabel(dmB, name, &labelOld);
8042: if (labelOld) {
8043: switch (emode) {
8044: case DM_COPY_LABELS_KEEP:
8045: continue;
8046: case DM_COPY_LABELS_REPLACE:
8047: DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
8048: break;
8049: case DM_COPY_LABELS_FAIL:
8050: SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
8051: default:
8052: SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
8053: }
8054: }
8055: if (mode==PETSC_COPY_VALUES) {
8056: DMLabelDuplicate(label, &labelNew);
8057: } else {
8058: labelNew = label;
8059: }
8060: DMAddLabel(dmB, labelNew);
8061: if (mode==PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
8062: }
8063: return 0;
8064: }
8066: /*@C
8067: DMCompareLabels - Compare labels of two DMPlex meshes
8069: Collective
8071: Input Parameters:
8072: + dm0 - First DM object
8073: - dm1 - Second DM object
8075: Output Parameters
8076: + equal - (Optional) Flag whether labels of dm0 and dm1 are the same
8077: - message - (Optional) Message describing the difference, or NULL if there is no difference
8079: Level: intermediate
8081: Notes:
8082: The output flag equal is the same on all processes.
8083: If it is passed as NULL and difference is found, an error is thrown on all processes.
8084: Make sure to pass NULL on all processes.
8086: The output message is set independently on each rank.
8087: It is set to NULL if no difference was found on the current rank. It must be freed by user.
8088: If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner.
8089: Make sure to pass NULL on all processes.
8091: Labels are matched by name. If the number of labels and their names are equal,
8092: DMLabelCompare() is used to compare each pair of labels with the same name.
8094: Fortran Notes:
8095: This function is currently not available from Fortran.
8097: .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare()
8098: @*/
8099: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
8100: {
8101: PetscInt n, i;
8102: char msg[PETSC_MAX_PATH_LEN] = "";
8103: PetscBool eq;
8104: MPI_Comm comm;
8105: PetscMPIInt rank;
8112: PetscObjectGetComm((PetscObject)dm0, &comm);
8113: MPI_Comm_rank(comm, &rank);
8114: {
8115: PetscInt n1;
8117: DMGetNumLabels(dm0, &n);
8118: DMGetNumLabels(dm1, &n1);
8119: eq = (PetscBool) (n == n1);
8120: if (!eq) {
8121: PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %D != %D = Number of labels in dm1", n, n1);
8122: }
8123: MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
8124: if (!eq) goto finish;
8125: }
8126: for (i=0; i<n; i++) {
8127: DMLabel l0, l1;
8128: const char *name;
8129: char *msgInner;
8131: /* Ignore label order */
8132: DMGetLabelByNum(dm0, i, &l0);
8133: PetscObjectGetName((PetscObject)l0, &name);
8134: DMGetLabel(dm1, name, &l1);
8135: if (!l1) {
8136: PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%D in dm0) not found in dm1", name, i);
8137: eq = PETSC_FALSE;
8138: break;
8139: }
8140: DMLabelCompare(comm, l0, l1, &eq, &msgInner);
8141: PetscStrncpy(msg, msgInner, sizeof(msg));
8142: PetscFree(msgInner);
8143: if (!eq) break;
8144: }
8145: MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
8146: finish:
8147: /* If message output arg not set, print to stderr */
8148: if (message) {
8149: *message = NULL;
8150: if (msg[0]) {
8151: PetscStrallocpy(msg, message);
8152: }
8153: } else {
8154: if (msg[0]) {
8155: PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
8156: }
8157: PetscSynchronizedFlush(comm, PETSC_STDERR);
8158: }
8159: /* If same output arg not ser and labels are not equal, throw error */
8160: if (equal) *equal = eq;
8162: return 0;
8163: }
8165: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8166: {
8168: if (!*label) {
8169: DMCreateLabel(dm, name);
8170: DMGetLabel(dm, name, label);
8171: }
8172: DMLabelSetValue(*label, point, value);
8173: return 0;
8174: }
8176: /*
8177: Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8178: like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8179: (label, id) pair in the DM.
8181: However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8182: each label.
8183: */
8184: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8185: {
8186: DMUniversalLabel ul;
8187: PetscBool *active;
8188: PetscInt pStart, pEnd, p, Nl, l, m;
8190: PetscMalloc1(1, &ul);
8191: DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8192: DMGetNumLabels(dm, &Nl);
8193: PetscCalloc1(Nl, &active);
8194: ul->Nl = 0;
8195: for (l = 0; l < Nl; ++l) {
8196: PetscBool isdepth, iscelltype;
8197: const char *name;
8199: DMGetLabelName(dm, l, &name);
8200: PetscStrncmp(name, "depth", 6, &isdepth);
8201: PetscStrncmp(name, "celltype", 9, &iscelltype);
8202: active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8203: if (active[l]) ++ul->Nl;
8204: }
8205: PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8206: ul->Nv = 0;
8207: for (l = 0, m = 0; l < Nl; ++l) {
8208: DMLabel label;
8209: PetscInt nv;
8210: const char *name;
8212: if (!active[l]) continue;
8213: DMGetLabelName(dm, l, &name);
8214: DMGetLabelByNum(dm, l, &label);
8215: DMLabelGetNumValues(label, &nv);
8216: PetscStrallocpy(name, &ul->names[m]);
8217: ul->indices[m] = l;
8218: ul->Nv += nv;
8219: ul->offsets[m+1] = nv;
8220: ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1));
8221: ++m;
8222: }
8223: for (l = 1; l <= ul->Nl; ++l) {
8224: ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8225: ul->bits[l] = ul->bits[l-1] + ul->bits[l];
8226: }
8227: for (l = 0; l < ul->Nl; ++l) {
8228: PetscInt b;
8230: ul->masks[l] = 0;
8231: for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8232: }
8233: PetscMalloc1(ul->Nv, &ul->values);
8234: for (l = 0, m = 0; l < Nl; ++l) {
8235: DMLabel label;
8236: IS valueIS;
8237: const PetscInt *varr;
8238: PetscInt nv, v;
8240: if (!active[l]) continue;
8241: DMGetLabelByNum(dm, l, &label);
8242: DMLabelGetNumValues(label, &nv);
8243: DMLabelGetValueIS(label, &valueIS);
8244: ISGetIndices(valueIS, &varr);
8245: for (v = 0; v < nv; ++v) {
8246: ul->values[ul->offsets[m]+v] = varr[v];
8247: }
8248: ISRestoreIndices(valueIS, &varr);
8249: ISDestroy(&valueIS);
8250: PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8251: ++m;
8252: }
8253: DMPlexGetChart(dm, &pStart, &pEnd);
8254: for (p = pStart; p < pEnd; ++p) {
8255: PetscInt uval = 0;
8256: PetscBool marked = PETSC_FALSE;
8258: for (l = 0, m = 0; l < Nl; ++l) {
8259: DMLabel label;
8260: PetscInt val, defval, loc, nv;
8262: if (!active[l]) continue;
8263: DMGetLabelByNum(dm, l, &label);
8264: DMLabelGetValue(label, p, &val);
8265: DMLabelGetDefaultValue(label, &defval);
8266: if (val == defval) {++m; continue;}
8267: nv = ul->offsets[m+1]-ul->offsets[m];
8268: marked = PETSC_TRUE;
8269: PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8271: uval += (loc+1) << ul->bits[m];
8272: ++m;
8273: }
8274: if (marked) DMLabelSetValue(ul->label, p, uval);
8275: }
8276: PetscFree(active);
8277: *universal = ul;
8278: return 0;
8279: }
8281: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8282: {
8283: PetscInt l;
8285: for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
8286: DMLabelDestroy(&(*universal)->label);
8287: PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8288: PetscFree((*universal)->values);
8289: PetscFree(*universal);
8290: *universal = NULL;
8291: return 0;
8292: }
8294: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8295: {
8297: *ulabel = ul->label;
8298: return 0;
8299: }
8301: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8302: {
8303: PetscInt Nl = ul->Nl, l;
8306: for (l = 0; l < Nl; ++l) {
8307: if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
8308: else DMCreateLabel(dm, ul->names[l]);
8309: }
8310: if (preserveOrder) {
8311: for (l = 0; l < ul->Nl; ++l) {
8312: const char *name;
8313: PetscBool match;
8315: DMGetLabelName(dm, ul->indices[l], &name);
8316: PetscStrcmp(name, ul->names[l], &match);
8318: }
8319: }
8320: return 0;
8321: }
8323: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8324: {
8325: PetscInt l;
8327: for (l = 0; l < ul->Nl; ++l) {
8328: DMLabel label;
8329: PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8331: if (lval) {
8332: if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
8333: else DMGetLabel(dm, ul->names[l], &label);
8334: DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8335: }
8336: }
8337: return 0;
8338: }
8340: /*@
8341: DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8343: Input Parameter:
8344: . dm - The DM object
8346: Output Parameter:
8347: . cdm - The coarse DM
8349: Level: intermediate
8351: .seealso: DMSetCoarseDM()
8352: @*/
8353: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8354: {
8357: *cdm = dm->coarseMesh;
8358: return 0;
8359: }
8361: /*@
8362: DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8364: Input Parameters:
8365: + dm - The DM object
8366: - cdm - The coarse DM
8368: Level: intermediate
8370: .seealso: DMGetCoarseDM()
8371: @*/
8372: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8373: {
8376: PetscObjectReference((PetscObject)cdm);
8377: DMDestroy(&dm->coarseMesh);
8378: dm->coarseMesh = cdm;
8379: return 0;
8380: }
8382: /*@
8383: DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8385: Input Parameter:
8386: . dm - The DM object
8388: Output Parameter:
8389: . fdm - The fine DM
8391: Level: intermediate
8393: .seealso: DMSetFineDM()
8394: @*/
8395: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8396: {
8399: *fdm = dm->fineMesh;
8400: return 0;
8401: }
8403: /*@
8404: DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8406: Input Parameters:
8407: + dm - The DM object
8408: - fdm - The fine DM
8410: Level: intermediate
8412: .seealso: DMGetFineDM()
8413: @*/
8414: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8415: {
8418: PetscObjectReference((PetscObject)fdm);
8419: DMDestroy(&dm->fineMesh);
8420: dm->fineMesh = fdm;
8421: return 0;
8422: }
8424: /*=== DMBoundary code ===*/
8426: /*@C
8427: DMAddBoundary - Add a boundary condition to the model
8429: Collective on dm
8431: Input Parameters:
8432: + dm - The DM, with a PetscDS that matches the problem being constrained
8433: . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8434: . name - The BC name
8435: . label - The label defining constrained points
8436: . Nv - The number of DMLabel values for constrained points
8437: . values - An array of values for constrained points
8438: . field - The field to constrain
8439: . Nc - The number of constrained field components (0 will constrain all fields)
8440: . comps - An array of constrained component numbers
8441: . bcFunc - A pointwise function giving boundary values
8442: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8443: - ctx - An optional user context for bcFunc
8445: Output Parameter:
8446: . bd - (Optional) Boundary number
8448: Options Database Keys:
8449: + -bc_<boundary name> <num> - Overrides the boundary ids
8450: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8452: Note:
8453: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8455: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8457: If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8459: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8460: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8461: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8462: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
8464: + dim - the spatial dimension
8465: . Nf - the number of fields
8466: . uOff - the offset into u[] and u_t[] for each field
8467: . uOff_x - the offset into u_x[] for each field
8468: . u - each field evaluated at the current point
8469: . u_t - the time derivative of each field evaluated at the current point
8470: . u_x - the gradient of each field evaluated at the current point
8471: . aOff - the offset into a[] and a_t[] for each auxiliary field
8472: . aOff_x - the offset into a_x[] for each auxiliary field
8473: . a - each auxiliary field evaluated at the current point
8474: . a_t - the time derivative of each auxiliary field evaluated at the current point
8475: . a_x - the gradient of auxiliary each field evaluated at the current point
8476: . t - current time
8477: . x - coordinates of the current point
8478: . numConstants - number of constant parameters
8479: . constants - constant parameters
8480: - bcval - output values at the current point
8482: Level: intermediate
8484: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8485: @*/
8486: 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)
8487: {
8488: PetscDS ds;
8496: DMGetDS(dm, &ds);
8497: DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8498: PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8499: return 0;
8500: }
8502: /* TODO Remove this since now the structures are the same */
8503: static PetscErrorCode DMPopulateBoundary(DM dm)
8504: {
8505: PetscDS ds;
8506: DMBoundary *lastnext;
8507: DSBoundary dsbound;
8509: DMGetDS(dm, &ds);
8510: dsbound = ds->boundary;
8511: if (dm->boundary) {
8512: DMBoundary next = dm->boundary;
8514: /* quick check to see if the PetscDS has changed */
8515: if (next->dsboundary == dsbound) return 0;
8516: /* the PetscDS has changed: tear down and rebuild */
8517: while (next) {
8518: DMBoundary b = next;
8520: next = b->next;
8521: PetscFree(b);
8522: }
8523: dm->boundary = NULL;
8524: }
8526: lastnext = &(dm->boundary);
8527: while (dsbound) {
8528: DMBoundary dmbound;
8530: PetscNew(&dmbound);
8531: dmbound->dsboundary = dsbound;
8532: dmbound->label = dsbound->label;
8533: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8534: *lastnext = dmbound;
8535: lastnext = &(dmbound->next);
8536: dsbound = dsbound->next;
8537: }
8538: return 0;
8539: }
8541: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8542: {
8543: DMBoundary b;
8547: *isBd = PETSC_FALSE;
8548: DMPopulateBoundary(dm);
8549: b = dm->boundary;
8550: while (b && !(*isBd)) {
8551: DMLabel label = b->label;
8552: DSBoundary dsb = b->dsboundary;
8553: PetscInt i;
8555: if (label) {
8556: for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
8557: }
8558: b = b->next;
8559: }
8560: return 0;
8561: }
8563: /*@C
8564: DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8566: Collective on DM
8568: Input Parameters:
8569: + dm - The DM
8570: . time - The time
8571: . funcs - The coordinate functions to evaluate, one per field
8572: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8573: - mode - The insertion mode for values
8575: Output Parameter:
8576: . X - vector
8578: Calling sequence of func:
8579: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8581: + dim - The spatial dimension
8582: . time - The time at which to sample
8583: . x - The coordinates
8584: . Nc - The number of components
8585: . u - The output field values
8586: - ctx - optional user-defined function context
8588: Level: developer
8590: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8591: @*/
8592: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8593: {
8594: Vec localX;
8597: DMGetLocalVector(dm, &localX);
8598: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8599: DMLocalToGlobalBegin(dm, localX, mode, X);
8600: DMLocalToGlobalEnd(dm, localX, mode, X);
8601: DMRestoreLocalVector(dm, &localX);
8602: return 0;
8603: }
8605: /*@C
8606: DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8608: Not collective
8610: Input Parameters:
8611: + dm - The DM
8612: . time - The time
8613: . funcs - The coordinate functions to evaluate, one per field
8614: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8615: - mode - The insertion mode for values
8617: Output Parameter:
8618: . localX - vector
8620: Calling sequence of func:
8621: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8623: + dim - The spatial dimension
8624: . x - The coordinates
8625: . Nc - The number of components
8626: . u - The output field values
8627: - ctx - optional user-defined function context
8629: Level: developer
8631: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8632: @*/
8633: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8634: {
8638: (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8639: return 0;
8640: }
8642: /*@C
8643: DMProjectFunctionLabel - This projects the given function into the function space provided, putting the coefficients in a global vector, setting values only for points in the given label.
8645: Collective on DM
8647: Input Parameters:
8648: + dm - The DM
8649: . time - The time
8650: . label - The DMLabel selecting the portion of the mesh for projection
8651: . funcs - The coordinate functions to evaluate, one per field
8652: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8653: - mode - The insertion mode for values
8655: Output Parameter:
8656: . X - vector
8658: Calling sequence of func:
8659: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8661: + dim - The spatial dimension
8662: . x - The coordinates
8663: . Nc - The number of components
8664: . u - The output field values
8665: - ctx - optional user-defined function context
8667: Level: developer
8669: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8670: @*/
8671: 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)
8672: {
8673: Vec localX;
8676: DMGetLocalVector(dm, &localX);
8677: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8678: DMLocalToGlobalBegin(dm, localX, mode, X);
8679: DMLocalToGlobalEnd(dm, localX, mode, X);
8680: DMRestoreLocalVector(dm, &localX);
8681: return 0;
8682: }
8684: /*@C
8685: DMProjectFunctionLabelLocal - This projects the given function into the function space provided, putting the coefficients in a local vector, setting values only for points in the given label.
8687: Not collective
8689: Input Parameters:
8690: + dm - The DM
8691: . time - The time
8692: . label - The DMLabel selecting the portion of the mesh for projection
8693: . funcs - The coordinate functions to evaluate, one per field
8694: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8695: - mode - The insertion mode for values
8697: Output Parameter:
8698: . localX - vector
8700: Calling sequence of func:
8701: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8703: + dim - The spatial dimension
8704: . x - The coordinates
8705: . Nc - The number of components
8706: . u - The output field values
8707: - ctx - optional user-defined function context
8709: Level: developer
8711: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8712: @*/
8713: 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)
8714: {
8718: (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8719: return 0;
8720: }
8722: /*@C
8723: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8725: Not collective
8727: Input Parameters:
8728: + dm - The DM
8729: . time - The time
8730: . localU - The input field vector
8731: . funcs - The functions to evaluate, one per field
8732: - mode - The insertion mode for values
8734: Output Parameter:
8735: . localX - The output vector
8737: Calling sequence of func:
8738: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8739: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8740: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8741: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8743: + dim - The spatial dimension
8744: . Nf - The number of input fields
8745: . NfAux - The number of input auxiliary fields
8746: . uOff - The offset of each field in u[]
8747: . uOff_x - The offset of each field in u_x[]
8748: . u - The field values at this point in space
8749: . u_t - The field time derivative at this point in space (or NULL)
8750: . u_x - The field derivatives at this point in space
8751: . aOff - The offset of each auxiliary field in u[]
8752: . aOff_x - The offset of each auxiliary field in u_x[]
8753: . a - The auxiliary field values at this point in space
8754: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8755: . a_x - The auxiliary field derivatives at this point in space
8756: . t - The current time
8757: . x - The coordinates of this point
8758: . numConstants - The number of constants
8759: . constants - The value of each constant
8760: - f - The value of the function at this point in space
8762: Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8763: 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
8764: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8765: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8767: Level: intermediate
8769: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8770: @*/
8771: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8772: void (**funcs)(PetscInt, PetscInt, PetscInt,
8773: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8774: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8775: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8776: InsertMode mode, Vec localX)
8777: {
8782: (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8783: return 0;
8784: }
8786: /*@C
8787: 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.
8789: Not collective
8791: Input Parameters:
8792: + dm - The DM
8793: . time - The time
8794: . label - The DMLabel marking the portion of the domain to output
8795: . numIds - The number of label ids to use
8796: . ids - The label ids to use for marking
8797: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8798: . comps - The components to set in the output, or NULL for all components
8799: . localU - The input field vector
8800: . funcs - The functions to evaluate, one per field
8801: - mode - The insertion mode for values
8803: Output Parameter:
8804: . localX - The output vector
8806: Calling sequence of func:
8807: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8808: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8809: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8810: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8812: + dim - The spatial dimension
8813: . Nf - The number of input fields
8814: . NfAux - The number of input auxiliary fields
8815: . uOff - The offset of each field in u[]
8816: . uOff_x - The offset of each field in u_x[]
8817: . u - The field values at this point in space
8818: . u_t - The field time derivative at this point in space (or NULL)
8819: . u_x - The field derivatives at this point in space
8820: . aOff - The offset of each auxiliary field in u[]
8821: . aOff_x - The offset of each auxiliary field in u_x[]
8822: . a - The auxiliary field values at this point in space
8823: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8824: . a_x - The auxiliary field derivatives at this point in space
8825: . t - The current time
8826: . x - The coordinates of this point
8827: . numConstants - The number of constants
8828: . constants - The value of each constant
8829: - f - The value of the function at this point in space
8831: Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8832: 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
8833: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8834: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8836: Level: intermediate
8838: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8839: @*/
8840: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8841: void (**funcs)(PetscInt, PetscInt, PetscInt,
8842: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8843: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8844: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8845: InsertMode mode, Vec localX)
8846: {
8851: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8852: return 0;
8853: }
8855: /*@C
8856: 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.
8858: Not collective
8860: Input Parameters:
8861: + dm - The DM
8862: . time - The time
8863: . label - The DMLabel marking the portion of the domain boundary to output
8864: . numIds - The number of label ids to use
8865: . ids - The label ids to use for marking
8866: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8867: . comps - The components to set in the output, or NULL for all components
8868: . localU - The input field vector
8869: . funcs - The functions to evaluate, one per field
8870: - mode - The insertion mode for values
8872: Output Parameter:
8873: . localX - The output vector
8875: Calling sequence of func:
8876: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8877: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8878: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8879: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8881: + dim - The spatial dimension
8882: . Nf - The number of input fields
8883: . NfAux - The number of input auxiliary fields
8884: . uOff - The offset of each field in u[]
8885: . uOff_x - The offset of each field in u_x[]
8886: . u - The field values at this point in space
8887: . u_t - The field time derivative at this point in space (or NULL)
8888: . u_x - The field derivatives at this point in space
8889: . aOff - The offset of each auxiliary field in u[]
8890: . aOff_x - The offset of each auxiliary field in u_x[]
8891: . a - The auxiliary field values at this point in space
8892: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8893: . a_x - The auxiliary field derivatives at this point in space
8894: . t - The current time
8895: . x - The coordinates of this point
8896: . n - The face normal
8897: . numConstants - The number of constants
8898: . constants - The value of each constant
8899: - f - The value of the function at this point in space
8901: Note:
8902: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8903: 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
8904: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8905: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8907: Level: intermediate
8909: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8910: @*/
8911: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8912: void (**funcs)(PetscInt, PetscInt, PetscInt,
8913: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8914: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8915: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8916: InsertMode mode, Vec localX)
8917: {
8922: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8923: return 0;
8924: }
8926: /*@C
8927: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8929: Input Parameters:
8930: + dm - The DM
8931: . time - The time
8932: . funcs - The functions to evaluate for each field component
8933: . ctxs - Optional array of contexts to pass to each function, or NULL.
8934: - X - The coefficient vector u_h, a global vector
8936: Output Parameter:
8937: . diff - The diff ||u - u_h||_2
8939: Level: developer
8941: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8942: @*/
8943: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8944: {
8948: (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8949: return 0;
8950: }
8952: /*@C
8953: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8955: Collective on dm
8957: Input Parameters:
8958: + dm - The DM
8959: , time - The time
8960: . funcs - The gradient functions to evaluate for each field component
8961: . ctxs - Optional array of contexts to pass to each function, or NULL.
8962: . X - The coefficient vector u_h, a global vector
8963: - n - The vector to project along
8965: Output Parameter:
8966: . diff - The diff ||(grad u - grad u_h) . n||_2
8968: Level: developer
8970: .seealso: DMProjectFunction(), DMComputeL2Diff()
8971: @*/
8972: 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)
8973: {
8977: (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8978: return 0;
8979: }
8981: /*@C
8982: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8984: Collective on dm
8986: Input Parameters:
8987: + dm - The DM
8988: . time - The time
8989: . funcs - The functions to evaluate for each field component
8990: . ctxs - Optional array of contexts to pass to each function, or NULL.
8991: - X - The coefficient vector u_h, a global vector
8993: Output Parameter:
8994: . diff - The array of differences, ||u^f - u^f_h||_2
8996: Level: developer
8998: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8999: @*/
9000: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9001: {
9005: (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9006: return 0;
9007: }
9009: /*@C
9010: DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9012: Not Collective
9014: Input Parameter:
9015: . dm - The DM
9017: Output Parameters:
9018: + nranks - the number of neighbours
9019: - ranks - the neighbors ranks
9021: Notes:
9022: Do not free the array, it is freed when the DM is destroyed.
9024: Level: beginner
9026: .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9027: @*/
9028: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9029: {
9032: (dm->ops->getneighbors)(dm,nranks,ranks);
9033: return 0;
9034: }
9036: #include <petsc/private/matimpl.h>
9038: /*
9039: Converts the input vector to a ghosted vector and then calls the standard coloring code.
9040: This has be a different function because it requires DM which is not defined in the Mat library
9041: */
9042: PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9043: {
9044: if (coloring->ctype == IS_COLORING_LOCAL) {
9045: Vec x1local;
9046: DM dm;
9047: MatGetDM(J,&dm);
9049: DMGetLocalVector(dm,&x1local);
9050: DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9051: DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9052: x1 = x1local;
9053: }
9054: MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9055: if (coloring->ctype == IS_COLORING_LOCAL) {
9056: DM dm;
9057: MatGetDM(J,&dm);
9058: DMRestoreLocalVector(dm,&x1);
9059: }
9060: return 0;
9061: }
9063: /*@
9064: MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9066: Input Parameter:
9067: . coloring - the MatFDColoring object
9069: Developer Notes:
9070: this routine exists because the PETSc Mat library does not know about the DM objects
9072: Level: advanced
9074: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9075: @*/
9076: PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9077: {
9078: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9079: return 0;
9080: }
9082: /*@
9083: DMGetCompatibility - determine if two DMs are compatible
9085: Collective
9087: Input Parameters:
9088: + dm1 - the first DM
9089: - dm2 - the second DM
9091: Output Parameters:
9092: + compatible - whether or not the two DMs are compatible
9093: - set - whether or not the compatible value was set
9095: Notes:
9096: Two DMs are deemed compatible if they represent the same parallel decomposition
9097: of the same topology. This implies that the section (field data) on one
9098: "makes sense" with respect to the topology and parallel decomposition of the other.
9099: Loosely speaking, compatible DMs represent the same domain and parallel
9100: decomposition, but hold different data.
9102: Typically, one would confirm compatibility if intending to simultaneously iterate
9103: over a pair of vectors obtained from different DMs.
9105: For example, two DMDA objects are compatible if they have the same local
9106: and global sizes and the same stencil width. They can have different numbers
9107: of degrees of freedom per node. Thus, one could use the node numbering from
9108: either DM in bounds for a loop over vectors derived from either DM.
9110: Consider the operation of summing data living on a 2-dof DMDA to data living
9111: on a 1-dof DMDA, which should be compatible, as in the following snippet.
9112: .vb
9113: ...
9114: DMGetCompatibility(da1,da2,&compatible,&set);
9115: if (set && compatible) {
9116: DMDAVecGetArrayDOF(da1,vec1,&arr1);
9117: DMDAVecGetArrayDOF(da2,vec2,&arr2);
9118: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9119: for (j=y; j<y+n; ++j) {
9120: for (i=x; i<x+m, ++i) {
9121: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9122: }
9123: }
9124: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9125: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9126: } else {
9127: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9128: }
9129: ...
9130: .ve
9132: Checking compatibility might be expensive for a given implementation of DM,
9133: or might be impossible to unambiguously confirm or deny. For this reason,
9134: this function may decline to determine compatibility, and hence users should
9135: always check the "set" output parameter.
9137: A DM is always compatible with itself.
9139: In the current implementation, DMs which live on "unequal" communicators
9140: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9141: incompatible.
9143: This function is labeled "Collective," as information about all subdomains
9144: is required on each rank. However, in DM implementations which store all this
9145: information locally, this function may be merely "Logically Collective".
9147: Developer Notes:
9148: Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9149: iff B is compatible with A. Thus, this function checks the implementations
9150: of both dm and dmc (if they are of different types), attempting to determine
9151: compatibility. It is left to DM implementers to ensure that symmetry is
9152: preserved. The simplest way to do this is, when implementing type-specific
9153: logic for this function, is to check for existing logic in the implementation
9154: of other DM types and let *set = PETSC_FALSE if found.
9156: Level: advanced
9158: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9159: @*/
9161: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9162: {
9163: PetscMPIInt compareResult;
9164: DMType type,type2;
9165: PetscBool sameType;
9170: /* Declare a DM compatible with itself */
9171: if (dm1 == dm2) {
9172: *set = PETSC_TRUE;
9173: *compatible = PETSC_TRUE;
9174: return 0;
9175: }
9177: /* Declare a DM incompatible with a DM that lives on an "unequal"
9178: communicator. Note that this does not preclude compatibility with
9179: DMs living on "congruent" or "similar" communicators, but this must be
9180: determined by the implementation-specific logic */
9181: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9182: if (compareResult == MPI_UNEQUAL) {
9183: *set = PETSC_TRUE;
9184: *compatible = PETSC_FALSE;
9185: return 0;
9186: }
9188: /* Pass to the implementation-specific routine, if one exists. */
9189: if (dm1->ops->getcompatibility) {
9190: (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9191: if (*set) return 0;
9192: }
9194: /* If dm1 and dm2 are of different types, then attempt to check compatibility
9195: with an implementation of this function from dm2 */
9196: DMGetType(dm1,&type);
9197: DMGetType(dm2,&type2);
9198: PetscStrcmp(type,type2,&sameType);
9199: if (!sameType && dm2->ops->getcompatibility) {
9200: (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9201: } else {
9202: *set = PETSC_FALSE;
9203: }
9204: return 0;
9205: }
9207: /*@C
9208: DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9210: Logically Collective on DM
9212: Input Parameters:
9213: + DM - the DM
9214: . f - the monitor function
9215: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9216: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9218: Options Database Keys:
9219: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9220: does not cancel those set via the options database.
9222: Notes:
9223: Several different monitoring routines may be set by calling
9224: DMMonitorSet() multiple times; all will be called in the
9225: order in which they were set.
9227: Fortran Notes:
9228: Only a single monitor function can be set for each DM object
9230: Level: intermediate
9232: .seealso: DMMonitorCancel()
9233: @*/
9234: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9235: {
9236: PetscInt m;
9239: for (m = 0; m < dm->numbermonitors; ++m) {
9240: PetscBool identical;
9242: PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9243: if (identical) return 0;
9244: }
9246: dm->monitor[dm->numbermonitors] = f;
9247: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
9248: dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9249: return 0;
9250: }
9252: /*@
9253: DMMonitorCancel - Clears all the monitor functions for a DM object.
9255: Logically Collective on DM
9257: Input Parameter:
9258: . dm - the DM
9260: Options Database Key:
9261: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9262: into a code by calls to DMonitorSet(), but does not cancel those
9263: set via the options database
9265: Notes:
9266: There is no way to clear one specific monitor from a DM object.
9268: Level: intermediate
9270: .seealso: DMMonitorSet()
9271: @*/
9272: PetscErrorCode DMMonitorCancel(DM dm)
9273: {
9274: PetscInt m;
9277: for (m = 0; m < dm->numbermonitors; ++m) {
9278: if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
9279: }
9280: dm->numbermonitors = 0;
9281: return 0;
9282: }
9284: /*@C
9285: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9287: Collective on DM
9289: Input Parameters:
9290: + dm - DM object you wish to monitor
9291: . name - the monitor type one is seeking
9292: . help - message indicating what monitoring is done
9293: . manual - manual page for the monitor
9294: . monitor - the monitor function
9295: - 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
9297: Output Parameter:
9298: . flg - Flag set if the monitor was created
9300: Level: developer
9302: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9303: PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9304: PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9305: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9306: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9307: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9308: PetscOptionsFList(), PetscOptionsEList()
9309: @*/
9310: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9311: {
9312: PetscViewer viewer;
9313: PetscViewerFormat format;
9316: PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9317: if (*flg) {
9318: PetscViewerAndFormat *vf;
9320: PetscViewerAndFormatCreate(viewer, format, &vf);
9321: PetscObjectDereference((PetscObject) viewer);
9322: if (monitorsetup) (*monitorsetup)(dm, vf);
9323: DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9324: }
9325: return 0;
9326: }
9328: /*@
9329: DMMonitor - runs the user provided monitor routines, if they exist
9331: Collective on DM
9333: Input Parameters:
9334: . dm - The DM
9336: Level: developer
9338: .seealso: DMMonitorSet()
9339: @*/
9340: PetscErrorCode DMMonitor(DM dm)
9341: {
9342: PetscInt m;
9344: if (!dm) return 0;
9346: for (m = 0; m < dm->numbermonitors; ++m) {
9347: (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9348: }
9349: return 0;
9350: }
9352: /*@
9353: DMComputeError - Computes the error assuming the user has given exact solution functions
9355: Collective on DM
9357: Input Parameters:
9358: + dm - The DM
9359: - sol - The solution vector
9361: Input/Output Parameter:
9362: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9363: contains the error in each field
9365: Output Parameter:
9366: . errorVec - A vector to hold the cellwise error (may be NULL)
9368: Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9370: Level: developer
9372: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9373: @*/
9374: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9375: {
9376: PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9377: void **ctxs;
9378: PetscReal time;
9379: PetscInt Nf, f, Nds, s;
9381: DMGetNumFields(dm, &Nf);
9382: PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9383: DMGetNumDS(dm, &Nds);
9384: for (s = 0; s < Nds; ++s) {
9385: PetscDS ds;
9386: DMLabel label;
9387: IS fieldIS;
9388: const PetscInt *fields;
9389: PetscInt dsNf;
9391: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9392: PetscDSGetNumFields(ds, &dsNf);
9393: if (fieldIS) ISGetIndices(fieldIS, &fields);
9394: for (f = 0; f < dsNf; ++f) {
9395: const PetscInt field = fields[f];
9396: PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9397: }
9398: if (fieldIS) ISRestoreIndices(fieldIS, &fields);
9399: }
9400: for (f = 0; f < Nf; ++f) {
9402: }
9403: DMGetOutputSequenceNumber(dm, NULL, &time);
9404: if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
9405: if (errorVec) {
9406: DM edm;
9407: DMPolytopeType ct;
9408: PetscBool simplex;
9409: PetscInt dim, cStart, Nf;
9411: DMClone(dm, &edm);
9412: DMGetDimension(edm, &dim);
9413: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9414: DMPlexGetCellType(dm, cStart, &ct);
9415: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9416: DMGetNumFields(dm, &Nf);
9417: for (f = 0; f < Nf; ++f) {
9418: PetscFE fe, efe;
9419: PetscQuadrature q;
9420: const char *name;
9422: DMGetField(dm, f, NULL, (PetscObject *) &fe);
9423: PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9424: PetscObjectGetName((PetscObject) fe, &name);
9425: PetscObjectSetName((PetscObject) efe, name);
9426: PetscFEGetQuadrature(fe, &q);
9427: PetscFESetQuadrature(efe, q);
9428: DMSetField(edm, f, NULL, (PetscObject) efe);
9429: PetscFEDestroy(&efe);
9430: }
9431: DMCreateDS(edm);
9433: DMCreateGlobalVector(edm, errorVec);
9434: PetscObjectSetName((PetscObject) *errorVec, "Error");
9435: DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9436: DMDestroy(&edm);
9437: }
9438: PetscFree2(exactSol, ctxs);
9439: return 0;
9440: }
9442: /*@
9443: DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM
9445: Not collective
9447: Input Parameter:
9448: . dm - The DM
9450: Output Parameter:
9451: . numAux - The number of auxiliary data vectors
9453: Level: advanced
9455: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9456: @*/
9457: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9458: {
9460: PetscHMapAuxGetSize(dm->auxData, numAux);
9461: return 0;
9462: }
9464: /*@
9465: DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9467: Not collective
9469: Input Parameters:
9470: + dm - The DM
9471: . label - The DMLabel
9472: . value - The label value indicating the region
9473: - part - The equation part, or 0 if unused
9475: Output Parameter:
9476: . aux - The Vec holding auxiliary field data
9478: Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9480: Level: advanced
9482: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9483: @*/
9484: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9485: {
9486: PetscHashAuxKey key, wild = {NULL, 0, 0};
9487: PetscBool has;
9491: key.label = label;
9492: key.value = value;
9493: key.part = part;
9494: PetscHMapAuxHas(dm->auxData, key, &has);
9495: if (has) PetscHMapAuxGet(dm->auxData, key, aux);
9496: else PetscHMapAuxGet(dm->auxData, wild, aux);
9497: return 0;
9498: }
9500: /*@
9501: DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part
9503: Not collective
9505: Input Parameters:
9506: + dm - The DM
9507: . label - The DMLabel
9508: . value - The label value indicating the region
9509: . part - The equation part, or 0 if unused
9510: - aux - The Vec holding auxiliary field data
9512: Level: advanced
9514: .seealso: DMGetAuxiliaryVec()
9515: @*/
9516: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9517: {
9518: Vec old;
9519: PetscHashAuxKey key;
9523: key.label = label;
9524: key.value = value;
9525: key.part = part;
9526: PetscHMapAuxGet(dm->auxData, key, &old);
9527: PetscObjectReference((PetscObject) aux);
9528: PetscObjectDereference((PetscObject) old);
9529: if (!aux) PetscHMapAuxDel(dm->auxData, key);
9530: else PetscHMapAuxSet(dm->auxData, key, aux);
9531: return 0;
9532: }
9534: /*@C
9535: DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM
9537: Not collective
9539: Input Parameter:
9540: . dm - The DM
9542: Output Parameters:
9543: + labels - The DMLabels for each Vec
9544: . values - The label values for each Vec
9545: - parts - The equation parts for each Vec
9547: Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().
9549: Level: advanced
9551: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9552: @*/
9553: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9554: {
9555: PetscHashAuxKey *keys;
9556: PetscInt n, i, off = 0;
9562: DMGetNumAuxiliaryVec(dm, &n);
9563: PetscMalloc1(n, &keys);
9564: PetscHMapAuxGetKeys(dm->auxData, &off, keys);
9565: for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;}
9566: PetscFree(keys);
9567: return 0;
9568: }
9570: /*@
9571: DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM
9573: Not collective
9575: Input Parameter:
9576: . dm - The DM
9578: Output Parameter:
9579: . dmNew - The new DM, now with the same auxiliary data
9581: Level: advanced
9583: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9584: @*/
9585: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9586: {
9588: PetscHMapAuxDestroy(&dmNew->auxData);
9589: PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
9590: return 0;
9591: }
9593: /*@C
9594: DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9596: Not collective
9598: Input Parameters:
9599: + ct - The DMPolytopeType
9600: . sourceCone - The source arrangement of faces
9601: - targetCone - The target arrangement of faces
9603: Output Parameters:
9604: + ornt - The orientation which will take the source arrangement to the target arrangement
9605: - found - Flag indicating that a suitable orientation was found
9607: Level: advanced
9609: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
9610: @*/
9611: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9612: {
9613: const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9614: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9615: PetscInt o, c;
9617: if (!nO) {*ornt = 0; *found = PETSC_TRUE; return 0;}
9618: for (o = -nO; o < nO; ++o) {
9619: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9621: for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9622: if (c == cS) {*ornt = o; break;}
9623: }
9624: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9625: return 0;
9626: }
9628: /*@C
9629: DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9631: Not collective
9633: Input Parameters:
9634: + ct - The DMPolytopeType
9635: . sourceCone - The source arrangement of faces
9636: - targetCone - The target arrangement of faces
9638: Output Parameters:
9639: . ornt - The orientation which will take the source arrangement to the target arrangement
9641: Note: This function will fail if no suitable orientation can be found.
9643: Level: advanced
9645: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
9646: @*/
9647: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9648: {
9649: PetscBool found;
9651: DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
9653: return 0;
9654: }
9656: /*@C
9657: DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9659: Not collective
9661: Input Parameters:
9662: + ct - The DMPolytopeType
9663: . sourceVert - The source arrangement of vertices
9664: - targetVert - The target arrangement of vertices
9666: Output Parameters:
9667: + ornt - The orientation which will take the source arrangement to the target arrangement
9668: - found - Flag indicating that a suitable orientation was found
9670: Level: advanced
9672: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
9673: @*/
9674: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9675: {
9676: const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9677: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9678: PetscInt o, c;
9680: if (!nO) {*ornt = 0; *found = PETSC_TRUE; return 0;}
9681: for (o = -nO; o < nO; ++o) {
9682: const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9684: for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9685: if (c == cS) {*ornt = o; break;}
9686: }
9687: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9688: return 0;
9689: }
9691: /*@C
9692: DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9694: Not collective
9696: Input Parameters:
9697: + ct - The DMPolytopeType
9698: . sourceCone - The source arrangement of vertices
9699: - targetCone - The target arrangement of vertices
9701: Output Parameters:
9702: . ornt - The orientation which will take the source arrangement to the target arrangement
9704: Note: This function will fail if no suitable orientation can be found.
9706: Level: advanced
9708: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
9709: @*/
9710: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9711: {
9712: PetscBool found;
9714: DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
9716: return 0;
9717: }
9719: /*@C
9720: DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9722: Not collective
9724: Input Parameters:
9725: + ct - The DMPolytopeType
9726: - point - Coordinates of the point
9728: Output Parameters:
9729: . inside - Flag indicating whether the point is inside the reference cell of given type
9731: Level: advanced
9733: .seealso: DMLocatePoints()
9734: @*/
9735: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9736: {
9737: PetscReal sum = 0.0;
9738: PetscInt d;
9740: *inside = PETSC_TRUE;
9741: switch (ct) {
9742: case DM_POLYTOPE_TRIANGLE:
9743: case DM_POLYTOPE_TETRAHEDRON:
9744: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9745: if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
9746: sum += point[d];
9747: }
9748: if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9749: break;
9750: case DM_POLYTOPE_QUADRILATERAL:
9751: case DM_POLYTOPE_HEXAHEDRON:
9752: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9753: if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9754: break;
9755: default:
9756: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9757: }
9758: return 0;
9759: }