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};
26: /*@
27: DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
29: If you never call DMSetType() it will generate an
30: error when you try to use the vector.
32: Collective
34: Input Parameter:
35: . comm - The communicator for the DM object
37: Output Parameter:
38: . dm - The DM object
40: Level: beginner
42: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
43: @*/
44: PetscErrorCode DMCreate(MPI_Comm comm,DM *dm)
45: {
46: DM v;
47: PetscDS ds;
52: *dm = NULL;
53: DMInitializePackage();
55: PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);
57: v->setupcalled = PETSC_FALSE;
58: v->setfromoptionscalled = PETSC_FALSE;
59: v->ltogmap = NULL;
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->defaultConstraintSection = NULL;
72: v->defaultConstraintMat = NULL;
73: v->L = NULL;
74: v->maxCell = NULL;
75: v->bdtype = NULL;
76: v->dimEmbed = PETSC_DEFAULT;
77: v->dim = PETSC_DETERMINE;
78: {
79: PetscInt i;
80: for (i = 0; i < 10; ++i) {
81: v->nullspaceConstructors[i] = NULL;
82: v->nearnullspaceConstructors[i] = NULL;
83: }
84: }
85: PetscDSCreate(PETSC_COMM_SELF, &ds);
86: DMSetRegionDS(v, NULL, NULL, ds);
87: PetscDSDestroy(&ds);
88: PetscHMapAuxCreate(&v->auxData);
89: v->dmBC = NULL;
90: v->coarseMesh = NULL;
91: v->outputSequenceNum = -1;
92: v->outputSequenceVal = 0.0;
93: DMSetVecType(v,VECSTANDARD);
94: DMSetMatType(v,MATAIJ);
96: *dm = v;
97: return(0);
98: }
100: /*@
101: DMClone - Creates a DM object with the same topology as the original.
103: Collective
105: Input Parameter:
106: . dm - The original DM object
108: Output Parameter:
109: . newdm - The new DM object
111: Level: beginner
113: Notes:
114: For some DM implementations this is a shallow clone, the result of which may share (referent counted) information with its parent. For example,
115: DMClone() applied to a DMPLEX object will result in a new DMPLEX that shares the topology with the original DMPLEX. It does not
116: share the PetscSection of the original DM.
118: The clone is considered set up iff the original is.
120: .seealso: DMDestroy(), DMCreate(), DMSetType(), DMSetLocalSection(), DMSetGlobalSection()
122: @*/
123: PetscErrorCode DMClone(DM dm, DM *newdm)
124: {
125: PetscSF sf;
126: Vec coords;
127: void *ctx;
128: PetscInt dim, cdim;
134: DMCreate(PetscObjectComm((PetscObject) dm), newdm);
135: DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
136: (*newdm)->leveldown = dm->leveldown;
137: (*newdm)->levelup = dm->levelup;
138: (*newdm)->prealloc_only = dm->prealloc_only;
139: PetscFree((*newdm)->vectype);
140: PetscStrallocpy(dm->vectype,(char**)&(*newdm)->vectype);
141: PetscFree((*newdm)->mattype);
142: PetscStrallocpy(dm->mattype,(char**)&(*newdm)->mattype);
143: DMGetDimension(dm, &dim);
144: DMSetDimension(*newdm, dim);
145: if (dm->ops->clone) {
146: (*dm->ops->clone)(dm, newdm);
147: }
148: (*newdm)->setupcalled = dm->setupcalled;
149: DMGetPointSF(dm, &sf);
150: DMSetPointSF(*newdm, sf);
151: DMGetApplicationContext(dm, &ctx);
152: DMSetApplicationContext(*newdm, ctx);
153: if (dm->coordinateDM) {
154: DM ncdm;
155: PetscSection cs;
156: PetscInt pEnd = -1, pEndMax = -1;
158: DMGetLocalSection(dm->coordinateDM, &cs);
159: if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
160: MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
161: if (pEndMax >= 0) {
162: DMClone(dm->coordinateDM, &ncdm);
163: DMCopyDisc(dm->coordinateDM, ncdm);
164: DMSetLocalSection(ncdm, cs);
165: DMSetCoordinateDM(*newdm, ncdm);
166: DMDestroy(&ncdm);
167: }
168: }
169: DMGetCoordinateDim(dm, &cdim);
170: DMSetCoordinateDim(*newdm, cdim);
171: DMGetCoordinatesLocal(dm, &coords);
172: if (coords) {
173: DMSetCoordinatesLocal(*newdm, coords);
174: } else {
175: DMGetCoordinates(dm, &coords);
176: if (coords) {DMSetCoordinates(*newdm, coords);}
177: }
178: {
179: PetscBool isper;
180: const PetscReal *maxCell, *L;
181: const DMBoundaryType *bd;
182: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
183: DMSetPeriodicity(*newdm, isper, maxCell, L, bd);
184: }
185: {
186: PetscBool useCone, useClosure;
188: DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
189: DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
190: }
191: return(0);
192: }
194: /*@C
195: DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
197: Logically Collective on da
199: Input Parameter:
200: + da - initial distributed array
201: . ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL
203: Options Database:
204: . -dm_vec_type ctype
206: Level: intermediate
208: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
209: @*/
210: PetscErrorCode DMSetVecType(DM da,VecType ctype)
211: {
216: PetscFree(da->vectype);
217: PetscStrallocpy(ctype,(char**)&da->vectype);
218: return(0);
219: }
221: /*@C
222: DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
224: Logically Collective on da
226: Input Parameter:
227: . da - initial distributed array
229: Output Parameter:
230: . ctype - the vector type
232: Level: intermediate
234: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
235: @*/
236: PetscErrorCode DMGetVecType(DM da,VecType *ctype)
237: {
240: *ctype = da->vectype;
241: return(0);
242: }
244: /*@
245: VecGetDM - Gets the DM defining the data layout of the vector
247: Not collective
249: Input Parameter:
250: . v - The Vec
252: Output Parameter:
253: . dm - The DM
255: Level: intermediate
257: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
258: @*/
259: PetscErrorCode VecGetDM(Vec v, DM *dm)
260: {
266: PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
267: return(0);
268: }
270: /*@
271: VecSetDM - Sets the DM defining the data layout of the vector.
273: Not collective
275: Input Parameters:
276: + v - The Vec
277: - dm - The DM
279: 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.
281: Level: intermediate
283: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
284: @*/
285: PetscErrorCode VecSetDM(Vec v, DM dm)
286: {
292: PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
293: return(0);
294: }
296: /*@C
297: DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM
299: Logically Collective on dm
301: Input Parameters:
302: + dm - the DM context
303: - ctype - the matrix type
305: Options Database:
306: . -dm_is_coloring_type - global or local
308: Level: intermediate
310: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
311: DMGetISColoringType()
312: @*/
313: PetscErrorCode DMSetISColoringType(DM dm,ISColoringType ctype)
314: {
317: dm->coloringtype = ctype;
318: return(0);
319: }
321: /*@C
322: DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM
324: Logically Collective on dm
326: Input Parameter:
327: . dm - the DM context
329: Output Parameter:
330: . ctype - the matrix type
332: Options Database:
333: . -dm_is_coloring_type - global or local
335: Level: intermediate
337: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
338: DMGetISColoringType()
339: @*/
340: PetscErrorCode DMGetISColoringType(DM dm,ISColoringType *ctype)
341: {
344: *ctype = dm->coloringtype;
345: return(0);
346: }
348: /*@C
349: DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
351: Logically Collective on dm
353: Input Parameters:
354: + dm - the DM context
355: - ctype - the matrix type
357: Options Database:
358: . -dm_mat_type ctype
360: Level: intermediate
362: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
363: @*/
364: PetscErrorCode DMSetMatType(DM dm,MatType ctype)
365: {
370: PetscFree(dm->mattype);
371: PetscStrallocpy(ctype,(char**)&dm->mattype);
372: return(0);
373: }
375: /*@C
376: DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
378: Logically Collective on dm
380: Input Parameter:
381: . dm - the DM context
383: Output Parameter:
384: . ctype - the matrix type
386: Options Database:
387: . -dm_mat_type ctype
389: Level: intermediate
391: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
392: @*/
393: PetscErrorCode DMGetMatType(DM dm,MatType *ctype)
394: {
397: *ctype = dm->mattype;
398: return(0);
399: }
401: /*@
402: MatGetDM - Gets the DM defining the data layout of the matrix
404: Not collective
406: Input Parameter:
407: . A - The Mat
409: Output Parameter:
410: . dm - The DM
412: Level: intermediate
414: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
415: the Mat through a PetscObjectCompose() operation
417: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
418: @*/
419: PetscErrorCode MatGetDM(Mat A, DM *dm)
420: {
426: PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
427: return(0);
428: }
430: /*@
431: MatSetDM - Sets the DM defining the data layout of the matrix
433: Not collective
435: Input Parameters:
436: + A - The Mat
437: - dm - The DM
439: Level: intermediate
441: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
442: the Mat through a PetscObjectCompose() operation
444: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
445: @*/
446: PetscErrorCode MatSetDM(Mat A, DM dm)
447: {
453: PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
454: return(0);
455: }
457: /*@C
458: DMSetOptionsPrefix - Sets the prefix used for searching for all
459: DM options in the database.
461: Logically Collective on dm
463: Input Parameters:
464: + da - the DM context
465: - prefix - the prefix to prepend to all option names
467: Notes:
468: A hyphen (-) must NOT be given at the beginning of the prefix name.
469: The first character of all runtime options is AUTOMATICALLY the hyphen.
471: Level: advanced
473: .seealso: DMSetFromOptions()
474: @*/
475: PetscErrorCode DMSetOptionsPrefix(DM dm,const char prefix[])
476: {
481: PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
482: if (dm->sf) {
483: PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
484: }
485: if (dm->sectionSF) {
486: PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
487: }
488: return(0);
489: }
491: /*@C
492: DMAppendOptionsPrefix - Appends to the prefix used for searching for all
493: DM options in the database.
495: Logically Collective on dm
497: Input Parameters:
498: + dm - the DM context
499: - prefix - the prefix string to prepend to all DM option requests
501: Notes:
502: A hyphen (-) must NOT be given at the beginning of the prefix name.
503: The first character of all runtime options is AUTOMATICALLY the hyphen.
505: Level: advanced
507: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
508: @*/
509: PetscErrorCode DMAppendOptionsPrefix(DM dm,const char prefix[])
510: {
515: PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
516: return(0);
517: }
519: /*@C
520: DMGetOptionsPrefix - Gets the prefix used for searching for all
521: DM options in the database.
523: Not Collective
525: Input Parameters:
526: . dm - the DM context
528: Output Parameters:
529: . prefix - pointer to the prefix string used is returned
531: Notes:
532: On the fortran side, the user should pass in a string 'prefix' of
533: sufficient length to hold the prefix.
535: Level: advanced
537: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
538: @*/
539: PetscErrorCode DMGetOptionsPrefix(DM dm,const char *prefix[])
540: {
545: PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
546: return(0);
547: }
549: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
550: {
551: PetscInt refct = ((PetscObject) dm)->refct;
555: *ncrefct = 0;
556: if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
557: refct--;
558: if (recurseCoarse) {
559: PetscInt coarseCount;
561: DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
562: refct += coarseCount;
563: }
564: }
565: if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
566: refct--;
567: if (recurseFine) {
568: PetscInt fineCount;
570: DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
571: refct += fineCount;
572: }
573: }
574: *ncrefct = refct;
575: return(0);
576: }
578: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
579: {
580: DMLabelLink next = dm->labels;
584: /* destroy the labels */
585: while (next) {
586: DMLabelLink tmp = next->next;
588: if (next->label == dm->depthLabel) dm->depthLabel = NULL;
589: if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
590: DMLabelDestroy(&next->label);
591: PetscFree(next);
592: next = tmp;
593: }
594: dm->labels = NULL;
595: return(0);
596: }
598: /*@C
599: DMDestroy - Destroys a vector packer or DM.
601: Collective on dm
603: Input Parameter:
604: . dm - the DM object to destroy
606: Level: developer
608: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
610: @*/
611: PetscErrorCode DMDestroy(DM *dm)
612: {
613: PetscInt cnt;
614: DMNamedVecLink nlink,nnext;
618: if (!*dm) return(0);
621: /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
622: DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
623: --((PetscObject)(*dm))->refct;
624: if (--cnt > 0) {*dm = NULL; return(0);}
625: if (((PetscObject)(*dm))->refct < 0) return(0);
626: ((PetscObject)(*dm))->refct = 0;
628: DMClearGlobalVectors(*dm);
629: DMClearLocalVectors(*dm);
631: nnext=(*dm)->namedglobal;
632: (*dm)->namedglobal = NULL;
633: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
634: nnext = nlink->next;
635: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
636: PetscFree(nlink->name);
637: VecDestroy(&nlink->X);
638: PetscFree(nlink);
639: }
640: nnext=(*dm)->namedlocal;
641: (*dm)->namedlocal = NULL;
642: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
643: nnext = nlink->next;
644: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
645: PetscFree(nlink->name);
646: VecDestroy(&nlink->X);
647: PetscFree(nlink);
648: }
650: /* Destroy the list of hooks */
651: {
652: DMCoarsenHookLink link,next;
653: for (link=(*dm)->coarsenhook; link; link=next) {
654: next = link->next;
655: PetscFree(link);
656: }
657: (*dm)->coarsenhook = NULL;
658: }
659: {
660: DMRefineHookLink link,next;
661: for (link=(*dm)->refinehook; link; link=next) {
662: next = link->next;
663: PetscFree(link);
664: }
665: (*dm)->refinehook = NULL;
666: }
667: {
668: DMSubDomainHookLink link,next;
669: for (link=(*dm)->subdomainhook; link; link=next) {
670: next = link->next;
671: PetscFree(link);
672: }
673: (*dm)->subdomainhook = NULL;
674: }
675: {
676: DMGlobalToLocalHookLink link,next;
677: for (link=(*dm)->gtolhook; link; link=next) {
678: next = link->next;
679: PetscFree(link);
680: }
681: (*dm)->gtolhook = NULL;
682: }
683: {
684: DMLocalToGlobalHookLink link,next;
685: for (link=(*dm)->ltoghook; link; link=next) {
686: next = link->next;
687: PetscFree(link);
688: }
689: (*dm)->ltoghook = NULL;
690: }
691: /* Destroy the work arrays */
692: {
693: DMWorkLink link,next;
694: if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
695: for (link=(*dm)->workin; link; link=next) {
696: next = link->next;
697: PetscFree(link->mem);
698: PetscFree(link);
699: }
700: (*dm)->workin = NULL;
701: }
702: /* destroy the labels */
703: DMDestroyLabelLinkList_Internal(*dm);
704: /* destroy the fields */
705: DMClearFields(*dm);
706: /* destroy the boundaries */
707: {
708: DMBoundary next = (*dm)->boundary;
709: while (next) {
710: DMBoundary b = next;
712: next = b->next;
713: PetscFree(b);
714: }
715: }
717: PetscObjectDestroy(&(*dm)->dmksp);
718: PetscObjectDestroy(&(*dm)->dmsnes);
719: PetscObjectDestroy(&(*dm)->dmts);
721: if ((*dm)->ctx && (*dm)->ctxdestroy) {
722: (*(*dm)->ctxdestroy)(&(*dm)->ctx);
723: }
724: MatFDColoringDestroy(&(*dm)->fd);
725: ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
726: PetscFree((*dm)->vectype);
727: PetscFree((*dm)->mattype);
729: PetscSectionDestroy(&(*dm)->localSection);
730: PetscSectionDestroy(&(*dm)->globalSection);
731: PetscLayoutDestroy(&(*dm)->map);
732: PetscSectionDestroy(&(*dm)->defaultConstraintSection);
733: MatDestroy(&(*dm)->defaultConstraintMat);
734: PetscSFDestroy(&(*dm)->sf);
735: PetscSFDestroy(&(*dm)->sectionSF);
736: if ((*dm)->useNatural) {
737: if ((*dm)->sfNatural) {
738: PetscSFDestroy(&(*dm)->sfNatural);
739: }
740: PetscObjectDereference((PetscObject) (*dm)->sfMigration);
741: }
742: {
743: Vec *auxData;
744: PetscInt n, i, off = 0;
746: PetscHMapAuxGetSize((*dm)->auxData, &n);
747: PetscMalloc1(n, &auxData);
748: PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
749: for (i = 0; i < n; ++i) {VecDestroy(&auxData[i]);}
750: PetscFree(auxData);
751: PetscHMapAuxDestroy(&(*dm)->auxData);
752: }
753: if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
754: DMSetFineDM((*dm)->coarseMesh,NULL);
755: }
757: DMDestroy(&(*dm)->coarseMesh);
758: if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
759: DMSetCoarseDM((*dm)->fineMesh,NULL);
760: }
761: DMDestroy(&(*dm)->fineMesh);
762: DMFieldDestroy(&(*dm)->coordinateField);
763: DMDestroy(&(*dm)->coordinateDM);
764: VecDestroy(&(*dm)->coordinates);
765: VecDestroy(&(*dm)->coordinatesLocal);
766: PetscFree((*dm)->L);
767: PetscFree((*dm)->maxCell);
768: PetscFree((*dm)->bdtype);
769: if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
770: DMDestroy(&(*dm)->transformDM);
771: VecDestroy(&(*dm)->transform);
773: DMClearDS(*dm);
774: DMDestroy(&(*dm)->dmBC);
775: /* if memory was published with SAWs then destroy it */
776: PetscObjectSAWsViewOff((PetscObject)*dm);
778: if ((*dm)->ops->destroy) {
779: (*(*dm)->ops->destroy)(*dm);
780: }
781: DMMonitorCancel(*dm);
782: #ifdef PETSC_HAVE_LIBCEED
783: CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
784: CeedDestroy(&(*dm)->ceed);
785: #endif
786: /* We do not destroy (*dm)->data here so that we can reference count backend objects */
787: PetscHeaderDestroy(dm);
788: return(0);
789: }
791: /*@
792: DMSetUp - sets up the data structures inside a DM object
794: Collective on dm
796: Input Parameter:
797: . dm - the DM object to setup
799: Level: developer
801: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
803: @*/
804: PetscErrorCode DMSetUp(DM dm)
805: {
810: if (dm->setupcalled) return(0);
811: if (dm->ops->setup) {
812: (*dm->ops->setup)(dm);
813: }
814: dm->setupcalled = PETSC_TRUE;
815: return(0);
816: }
818: /*@
819: DMSetFromOptions - sets parameters in a DM from the options database
821: Collective on dm
823: Input Parameter:
824: . dm - the DM object to set options for
826: Options Database:
827: + -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
828: . -dm_vec_type <type> - type of vector to create inside DM
829: . -dm_mat_type <type> - type of matrix to create inside DM
830: - -dm_is_coloring_type - <global or local>
832: DMPLEX Specific creation options
833: + -dm_plex_filename <str> - File containing a mesh
834: . -dm_plex_boundary_filename <str> - File containing a mesh boundary
835: . -dm_plex_shape <shape> - The domain shape, such as DM_SHAPE_BOX, DM_SHAPE_SPHERE, etc.
836: . -dm_plex_cell <ct> - Cell shape
837: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
838: . -dm_plex_dim <dim> - Set the topological dimension
839: . -dm_plex_simplex <bool> - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
840: . -dm_plex_interpolate <bool> - PETSC_TRUE turns on topological interpolation (creating edges and faces)
841: . -dm_plex_scale <sc> - Scale factor for mesh coordinates
842: . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension
843: . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box
844: . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box
845: . -dm_plex_box_bd <bx,by,bz> - Specify the DMBoundaryType for each direction
846: . -dm_plex_sphere_radius <r> - The sphere radius
847: . -dm_plex_ball_radius <r> - Radius of the ball
848: . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction
849: . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder
850: . -dm_refine_pre <n> - The number of refinements before distribution
851: . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution
852: . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution
853: . -dm_refine <n> - The number of refinements after distribution
854: . -dm_extrude_layers <l> - The number of layers to extrude
855: . -dm_extrude_thickness <t> - The thickness of the layer to be extruded
856: . -dm_extrude_column_first <bool> - Order the cells in a vertical column first
857: . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary
858: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
859: . -dm_distribute <bool> - Flag to redistribute a mesh among processes
860: . -dm_distribute_overlap <n> - The size of the overlap halo
861: . -dm_plex_adj_cone <bool> - Set adjacency direction
862: - -dm_plex_adj_closure <bool> - Set adjacency size
864: DMPLEX Specific Checks
865: + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
866: . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
867: . -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()
868: . -dm_plex_check_geometry - Check that cells have positive volume - DMPlexCheckGeometry()
869: . -dm_plex_check_pointsf - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
870: . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
871: - -dm_plex_check_all - Perform all the checks above
873: Level: intermediate
875: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(),
876: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces(), DMPlexCheckGeometry(), DMPlexCheckPointSF(), DMPlexCheckInterfaceCones()
878: @*/
879: PetscErrorCode DMSetFromOptions(DM dm)
880: {
881: char typeName[256];
882: PetscBool flg;
887: dm->setfromoptionscalled = PETSC_TRUE;
888: if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
889: if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
890: PetscObjectOptionsBegin((PetscObject)dm);
891: PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
892: PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
893: if (flg) {
894: DMSetVecType(dm,typeName);
895: }
896: PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
897: if (flg) {
898: DMSetMatType(dm,typeName);
899: }
900: PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
901: if (dm->ops->setfromoptions) {
902: (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
903: }
904: /* process any options handlers added with PetscObjectAddOptionsHandler() */
905: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
906: PetscOptionsEnd();
907: return(0);
908: }
910: /*@C
911: DMViewFromOptions - View from Options
913: Collective on DM
915: Input Parameters:
916: + dm - the DM object
917: . obj - Optional object
918: - name - command line option
920: Level: intermediate
921: .seealso: DM, DMView, PetscObjectViewFromOptions(), DMCreate()
922: @*/
923: PetscErrorCode DMViewFromOptions(DM dm,PetscObject obj,const char name[])
924: {
929: PetscObjectViewFromOptions((PetscObject)dm,obj,name);
930: return(0);
931: }
933: /*@C
934: DMView - Views a DM
936: Collective on dm
938: Input Parameters:
939: + dm - the DM object to view
940: - v - the viewer
942: Level: beginner
944: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
946: @*/
947: PetscErrorCode DMView(DM dm,PetscViewer v)
948: {
949: PetscErrorCode ierr;
950: PetscBool isbinary;
951: PetscMPIInt size;
952: PetscViewerFormat format;
956: if (!v) {
957: PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
958: }
960: /* Ideally, we would like to have this test on.
961: However, it currently breaks socket viz via GLVis.
962: During DMView(parallel_mesh,glvis_viewer), each
963: process opens a sequential ASCII socket to visualize
964: the local mesh, and PetscObjectView(dm,local_socket)
965: is internally called inside VecView_GLVis, incurring
966: in an error here */
968: PetscViewerCheckWritable(v);
970: PetscViewerGetFormat(v,&format);
971: MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
972: if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
973: PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
974: PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
975: if (isbinary) {
976: PetscInt classid = DM_FILE_CLASSID;
977: char type[256];
979: PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
980: PetscStrncpy(type,((PetscObject)dm)->type_name,256);
981: PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
982: }
983: if (dm->ops->view) {
984: (*dm->ops->view)(dm,v);
985: }
986: return(0);
987: }
989: /*@
990: DMCreateGlobalVector - Creates a global vector from a DM object
992: Collective on dm
994: Input Parameter:
995: . dm - the DM object
997: Output Parameter:
998: . vec - the global vector
1000: Level: beginner
1002: .seealso DMCreateLocalVector(), DMGetGlobalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1004: @*/
1005: PetscErrorCode DMCreateGlobalVector(DM dm,Vec *vec)
1006: {
1012: if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
1013: (*dm->ops->createglobalvector)(dm,vec);
1014: if (PetscDefined(USE_DEBUG)) {
1015: DM vdm;
1017: VecGetDM(*vec,&vdm);
1018: if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
1019: }
1020: return(0);
1021: }
1023: /*@
1024: DMCreateLocalVector - Creates a local vector from a DM object
1026: Not Collective
1028: Input Parameter:
1029: . dm - the DM object
1031: Output Parameter:
1032: . vec - the local vector
1034: Level: beginner
1036: .seealso DMCreateGlobalVector(), DMGetLocalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1038: @*/
1039: PetscErrorCode DMCreateLocalVector(DM dm,Vec *vec)
1040: {
1046: if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
1047: (*dm->ops->createlocalvector)(dm,vec);
1048: if (PetscDefined(USE_DEBUG)) {
1049: DM vdm;
1051: VecGetDM(*vec,&vdm);
1052: if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
1053: }
1054: return(0);
1055: }
1057: /*@
1058: DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
1060: Collective on dm
1062: Input Parameter:
1063: . dm - the DM that provides the mapping
1065: Output Parameter:
1066: . ltog - the mapping
1068: Level: intermediate
1070: Notes:
1071: This mapping can then be used by VecSetLocalToGlobalMapping() or
1072: MatSetLocalToGlobalMapping().
1074: .seealso: DMCreateLocalVector()
1075: @*/
1076: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1077: {
1078: PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1084: if (!dm->ltogmap) {
1085: PetscSection section, sectionGlobal;
1087: DMGetLocalSection(dm, §ion);
1088: if (section) {
1089: const PetscInt *cdofs;
1090: PetscInt *ltog;
1091: PetscInt pStart, pEnd, n, p, k, l;
1093: DMGetGlobalSection(dm, §ionGlobal);
1094: PetscSectionGetChart(section, &pStart, &pEnd);
1095: PetscSectionGetStorageSize(section, &n);
1096: PetscMalloc1(n, <og); /* We want the local+overlap size */
1097: for (p = pStart, l = 0; p < pEnd; ++p) {
1098: PetscInt bdof, cdof, dof, off, c, cind = 0;
1100: /* Should probably use constrained dofs */
1101: PetscSectionGetDof(section, p, &dof);
1102: PetscSectionGetConstraintDof(section, p, &cdof);
1103: PetscSectionGetConstraintIndices(section, p, &cdofs);
1104: PetscSectionGetOffset(sectionGlobal, p, &off);
1105: /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1106: bdof = cdof && (dof-cdof) ? 1 : dof;
1107: if (dof) {
1108: if (bs < 0) {bs = bdof;}
1109: else if (bs != bdof) {bs = 1;}
1110: }
1111: for (c = 0; c < dof; ++c, ++l) {
1112: if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1113: else ltog[l] = (off < 0 ? -(off+1) : off) + c;
1114: }
1115: }
1116: /* Must have same blocksize on all procs (some might have no points) */
1117: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1118: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1119: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1120: else {bs = bsMinMax[0];}
1121: bs = bs < 0 ? 1 : bs;
1122: /* Must reduce indices by blocksize */
1123: if (bs > 1) {
1124: for (l = 0, k = 0; l < n; l += bs, ++k) {
1125: // Integer division of negative values truncates toward zero(!), not toward negative infinity
1126: ltog[k] = ltog[l] >= 0 ? ltog[l]/bs : -(-(ltog[l]+1)/bs + 1);
1127: }
1128: n /= bs;
1129: }
1130: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1131: PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1132: } else {
1133: if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1134: (*dm->ops->getlocaltoglobalmapping)(dm);
1135: }
1136: }
1137: *ltog = dm->ltogmap;
1138: return(0);
1139: }
1141: /*@
1142: DMGetBlockSize - Gets the inherent block size associated with a DM
1144: Not Collective
1146: Input Parameter:
1147: . dm - the DM with block structure
1149: Output Parameter:
1150: . bs - the block size, 1 implies no exploitable block structure
1152: Level: intermediate
1154: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1155: @*/
1156: PetscErrorCode DMGetBlockSize(DM dm,PetscInt *bs)
1157: {
1161: if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1162: *bs = dm->bs;
1163: return(0);
1164: }
1166: /*@C
1167: DMCreateInterpolation - Gets interpolation matrix between two DM objects
1169: Collective on dmc
1171: Input Parameters:
1172: + dmc - the DM object
1173: - dmf - the second, finer DM object
1175: Output Parameters:
1176: + mat - the interpolation
1177: - vec - the scaling (optional)
1179: Level: developer
1181: Notes:
1182: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1183: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1185: For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1186: EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1188: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolationScale()
1190: @*/
1191: PetscErrorCode DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1192: {
1199: if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1200: PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1201: (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1202: PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1203: return(0);
1204: }
1206: /*@
1207: DMCreateInterpolationScale - Forms L = 1/(R*1) such that diag(L)*R preserves scale and is thus suitable for state (versus residual) restriction.
1209: Input Parameters:
1210: + dac - DM that defines a coarse mesh
1211: . daf - DM that defines a fine mesh
1212: - mat - the restriction (or interpolation operator) from fine to coarse
1214: Output Parameter:
1215: . scale - the scaled vector
1217: Level: developer
1219: .seealso: DMCreateInterpolation()
1221: @*/
1222: PetscErrorCode DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1223: {
1225: Vec fine;
1226: PetscScalar one = 1.0;
1229: DMCreateGlobalVector(daf,&fine);
1230: DMCreateGlobalVector(dac,scale);
1231: VecSet(fine,one);
1232: MatRestrict(mat,fine,*scale);
1233: VecDestroy(&fine);
1234: VecReciprocal(*scale);
1235: return(0);
1236: }
1238: /*@
1239: DMCreateRestriction - Gets restriction matrix between two DM objects
1241: Collective on dmc
1243: Input Parameters:
1244: + dmc - the DM object
1245: - dmf - the second, finer DM object
1247: Output Parameter:
1248: . mat - the restriction
1250: Level: developer
1252: Notes:
1253: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1254: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1256: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()
1258: @*/
1259: PetscErrorCode DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1260: {
1267: if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1268: PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1269: (*dmc->ops->createrestriction)(dmc,dmf,mat);
1270: PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1271: return(0);
1272: }
1274: /*@
1275: DMCreateInjection - Gets injection matrix between two DM objects
1277: Collective on dac
1279: Input Parameters:
1280: + dac - the DM object
1281: - daf - the second, finer DM object
1283: Output Parameter:
1284: . mat - the injection
1286: Level: developer
1288: Notes:
1289: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1290: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
1292: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
1294: @*/
1295: PetscErrorCode DMCreateInjection(DM dac,DM daf,Mat *mat)
1296: {
1303: if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1304: PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1305: (*dac->ops->createinjection)(dac,daf,mat);
1306: PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1307: return(0);
1308: }
1310: /*@
1311: DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j
1313: Collective on dac
1315: Input Parameters:
1316: + dac - the DM object
1317: - daf - the second, finer DM object
1319: Output Parameter:
1320: . mat - the interpolation
1322: Level: developer
1324: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1325: @*/
1326: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1327: {
1334: if (!dac->ops->createmassmatrix) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMassMatrix",((PetscObject)dac)->type_name);
1335: (*dac->ops->createmassmatrix)(dac, daf, mat);
1336: return(0);
1337: }
1339: /*@
1340: DMCreateColoring - Gets coloring for a DM
1342: Collective on dm
1344: Input Parameters:
1345: + dm - the DM object
1346: - ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL
1348: Output Parameter:
1349: . coloring - the coloring
1351: Notes:
1352: Coloring of matrices can be computed directly from the sparse matrix nonzero structure via the MatColoring object or from the mesh from which the
1353: matrix comes from. In general using the mesh produces a more optimal coloring (fewer colors).
1355: This produces a coloring with the distance of 2, see MatSetColoringDistance() which can be used for efficiently computing Jacobians with MatFDColoringCreate()
1357: Level: developer
1359: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType(), MatColoring, MatFDColoringCreate()
1361: @*/
1362: PetscErrorCode DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1363: {
1369: if (!dm->ops->getcoloring) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateColoring",((PetscObject)dm)->type_name);
1370: (*dm->ops->getcoloring)(dm,ctype,coloring);
1371: return(0);
1372: }
1374: /*@
1375: DMCreateMatrix - Gets empty Jacobian for a DM
1377: Collective on dm
1379: Input Parameter:
1380: . dm - the DM object
1382: Output Parameter:
1383: . mat - the empty Jacobian
1385: Level: beginner
1387: Options Database Keys:
1388: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1390: Notes:
1391: This properly preallocates the number of nonzeros in the sparse matrix so you
1392: do not need to do it yourself.
1394: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1395: the nonzero pattern call DMSetMatrixPreallocateOnly()
1397: For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1398: internally by PETSc.
1400: For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1401: the indices for the global numbering for DMDAs which is complicated.
1403: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1405: @*/
1406: PetscErrorCode DMCreateMatrix(DM dm,Mat *mat)
1407: {
1413: if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1414: MatInitializePackage();
1415: PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1416: (*dm->ops->creatematrix)(dm,mat);
1417: if (PetscDefined(USE_DEBUG)) {
1418: DM mdm;
1420: MatGetDM(*mat,&mdm);
1421: if (!mdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the matrix\n",((PetscObject)dm)->type_name);
1422: }
1423: /* Handle nullspace and near nullspace */
1424: if (dm->Nf) {
1425: MatNullSpace nullSpace;
1426: PetscInt Nf, f;
1428: DMGetNumFields(dm, &Nf);
1429: for (f = 0; f < Nf; ++f) {
1430: if (dm->nullspaceConstructors[f]) {
1431: (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1432: MatSetNullSpace(*mat, nullSpace);
1433: MatNullSpaceDestroy(&nullSpace);
1434: break;
1435: }
1436: }
1437: for (f = 0; f < Nf; ++f) {
1438: if (dm->nearnullspaceConstructors[f]) {
1439: (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1440: MatSetNearNullSpace(*mat, nullSpace);
1441: MatNullSpaceDestroy(&nullSpace);
1442: }
1443: }
1444: }
1445: PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1446: return(0);
1447: }
1449: /*@
1450: DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1451: preallocated but the nonzero structure and zero values will not be set.
1453: Logically Collective on dm
1455: Input Parameters:
1456: + dm - the DM
1457: - only - PETSC_TRUE if only want preallocation
1459: Level: developer
1461: Options Database Keys:
1462: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1464: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1465: @*/
1466: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1467: {
1470: dm->prealloc_only = only;
1471: return(0);
1472: }
1474: /*@
1475: DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1476: but the array for values will not be allocated.
1478: Logically Collective on dm
1480: Input Parameters:
1481: + dm - the DM
1482: - only - PETSC_TRUE if only want matrix stucture
1484: Level: developer
1485: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1486: @*/
1487: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1488: {
1491: dm->structure_only = only;
1492: return(0);
1493: }
1495: /*@C
1496: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1498: Not Collective
1500: Input Parameters:
1501: + dm - the DM object
1502: . count - The minimum size
1503: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1505: Output Parameter:
1506: . array - the work array
1508: Level: developer
1510: .seealso DMDestroy(), DMCreate()
1511: @*/
1512: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1513: {
1515: DMWorkLink link;
1516: 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()
1560: .seealso DMDestroy(), DMCreate()
1561: @*/
1562: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1563: {
1564: 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
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: Notes:
1592: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1593: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1594: $ dm - The present DM
1595: $ origField - The field number given above, in the original DM
1596: $ field - The field number in dm
1597: $ nullSpace - The nullspace for the given field
1599: This function is currently not available from Fortran.
1601: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1602: */
1603: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1604: {
1607: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1608: dm->nullspaceConstructors[field] = nullsp;
1609: return(0);
1610: }
1612: /*@C
1613: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL
1615: Not collective
1617: Input Parameters:
1618: + dm - The DM
1619: - field - The field number for the nullspace
1621: Output Parameter:
1622: . nullsp - A callback to create the nullspace
1624: Notes:
1625: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1626: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1627: $ dm - The present DM
1628: $ origField - The field number given above, in the original DM
1629: $ field - The field number in dm
1630: $ nullSpace - The nullspace for the given field
1632: This function is currently not available from Fortran.
1634: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1635: */
1636: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1637: {
1641: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1642: *nullsp = dm->nullspaceConstructors[field];
1643: return(0);
1644: }
1646: /*@C
1647: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field
1649: Logically collective on DM
1651: Input Parameters:
1652: + dm - The DM
1653: . field - The field number for the nullspace
1654: - nullsp - A callback to create the near-nullspace
1656: Notes:
1657: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1658: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1659: $ dm - The present DM
1660: $ origField - The field number given above, in the original DM
1661: $ field - The field number in dm
1662: $ nullSpace - The nullspace for the given field
1664: This function is currently not available from Fortran.
1666: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1667: */
1668: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1669: {
1672: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1673: dm->nearnullspaceConstructors[field] = nullsp;
1674: return(0);
1675: }
1677: /*@C
1678: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL
1680: Not collective
1682: Input Parameters:
1683: + dm - The DM
1684: - field - The field number for the nullspace
1686: Output Parameter:
1687: . nullsp - A callback to create the near-nullspace
1689: Notes:
1690: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1691: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1692: $ dm - The present DM
1693: $ origField - The field number given above, in the original DM
1694: $ field - The field number in dm
1695: $ nullSpace - The nullspace for the given field
1697: This function is currently not available from Fortran.
1699: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1700: */
1701: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1702: {
1706: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1707: *nullsp = dm->nearnullspaceConstructors[field];
1708: return(0);
1709: }
1711: /*@C
1712: DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1714: Not collective
1716: Input Parameter:
1717: . dm - the DM object
1719: Output Parameters:
1720: + numFields - The number of fields (or NULL if not requested)
1721: . fieldNames - The name for each field (or NULL if not requested)
1722: - fields - The global indices for each field (or NULL if not requested)
1724: Level: intermediate
1726: Notes:
1727: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1728: PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1729: PetscFree().
1731: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1732: @*/
1733: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1734: {
1735: PetscSection section, sectionGlobal;
1740: if (numFields) {
1742: *numFields = 0;
1743: }
1744: if (fieldNames) {
1746: *fieldNames = NULL;
1747: }
1748: if (fields) {
1750: *fields = NULL;
1751: }
1752: DMGetLocalSection(dm, §ion);
1753: if (section) {
1754: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1755: PetscInt nF, f, pStart, pEnd, p;
1757: DMGetGlobalSection(dm, §ionGlobal);
1758: PetscSectionGetNumFields(section, &nF);
1759: PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1760: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1761: for (f = 0; f < nF; ++f) {
1762: fieldSizes[f] = 0;
1763: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1764: }
1765: for (p = pStart; p < pEnd; ++p) {
1766: PetscInt gdof;
1768: PetscSectionGetDof(sectionGlobal, p, &gdof);
1769: if (gdof > 0) {
1770: for (f = 0; f < nF; ++f) {
1771: PetscInt fdof, fcdof, fpdof;
1773: PetscSectionGetFieldDof(section, p, f, &fdof);
1774: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1775: fpdof = fdof-fcdof;
1776: if (fpdof && fpdof != fieldNc[f]) {
1777: /* Layout does not admit a pointwise block size */
1778: fieldNc[f] = 1;
1779: }
1780: fieldSizes[f] += fpdof;
1781: }
1782: }
1783: }
1784: for (f = 0; f < nF; ++f) {
1785: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1786: fieldSizes[f] = 0;
1787: }
1788: for (p = pStart; p < pEnd; ++p) {
1789: PetscInt gdof, goff;
1791: PetscSectionGetDof(sectionGlobal, p, &gdof);
1792: if (gdof > 0) {
1793: PetscSectionGetOffset(sectionGlobal, p, &goff);
1794: for (f = 0; f < nF; ++f) {
1795: PetscInt fdof, fcdof, fc;
1797: PetscSectionGetFieldDof(section, p, f, &fdof);
1798: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1799: for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1800: fieldIndices[f][fieldSizes[f]] = goff++;
1801: }
1802: }
1803: }
1804: }
1805: if (numFields) *numFields = nF;
1806: if (fieldNames) {
1807: PetscMalloc1(nF, fieldNames);
1808: for (f = 0; f < nF; ++f) {
1809: const char *fieldName;
1811: PetscSectionGetFieldName(section, f, &fieldName);
1812: PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1813: }
1814: }
1815: if (fields) {
1816: PetscMalloc1(nF, fields);
1817: for (f = 0; f < nF; ++f) {
1818: PetscInt bs, in[2], out[2];
1820: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1821: in[0] = -fieldNc[f];
1822: in[1] = fieldNc[f];
1823: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1824: bs = (-out[0] == out[1]) ? out[1] : 1;
1825: ISSetBlockSize((*fields)[f], bs);
1826: }
1827: }
1828: PetscFree3(fieldSizes,fieldNc,fieldIndices);
1829: } else if (dm->ops->createfieldis) {
1830: (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1831: }
1832: return(0);
1833: }
1835: /*@C
1836: DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1837: corresponding to different fields: each IS contains the global indices of the dofs of the
1838: corresponding field. The optional list of DMs define the DM for each subproblem.
1839: Generalizes DMCreateFieldIS().
1841: Not collective
1843: Input Parameter:
1844: . dm - the DM object
1846: Output Parameters:
1847: + len - The number of subproblems in the field decomposition (or NULL if not requested)
1848: . namelist - The name for each field (or NULL if not requested)
1849: . islist - The global indices for each field (or NULL if not requested)
1850: - dmlist - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1852: Level: intermediate
1854: Notes:
1855: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1856: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1857: and all of the arrays should be freed with PetscFree().
1859: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1860: @*/
1861: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1862: {
1867: if (len) {
1869: *len = 0;
1870: }
1871: if (namelist) {
1873: *namelist = NULL;
1874: }
1875: if (islist) {
1877: *islist = NULL;
1878: }
1879: if (dmlist) {
1881: *dmlist = NULL;
1882: }
1883: /*
1884: Is it a good idea to apply the following check across all impls?
1885: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1886: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1887: */
1888: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1889: if (!dm->ops->createfielddecomposition) {
1890: PetscSection section;
1891: PetscInt numFields, f;
1893: DMGetLocalSection(dm, §ion);
1894: if (section) {PetscSectionGetNumFields(section, &numFields);}
1895: if (section && numFields && dm->ops->createsubdm) {
1896: if (len) *len = numFields;
1897: if (namelist) {PetscMalloc1(numFields,namelist);}
1898: if (islist) {PetscMalloc1(numFields,islist);}
1899: if (dmlist) {PetscMalloc1(numFields,dmlist);}
1900: for (f = 0; f < numFields; ++f) {
1901: const char *fieldName;
1903: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1904: if (namelist) {
1905: PetscSectionGetFieldName(section, f, &fieldName);
1906: PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1907: }
1908: }
1909: } else {
1910: DMCreateFieldIS(dm, len, namelist, islist);
1911: /* By default there are no DMs associated with subproblems. */
1912: if (dmlist) *dmlist = NULL;
1913: }
1914: } else {
1915: (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1916: }
1917: return(0);
1918: }
1920: /*@
1921: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1922: The fields are defined by DMCreateFieldIS().
1924: Not collective
1926: Input Parameters:
1927: + dm - The DM object
1928: . numFields - The number of fields in this subproblem
1929: - fields - The field numbers of the selected fields
1931: Output Parameters:
1932: + is - The global indices for the subproblem
1933: - subdm - The DM for the subproblem
1935: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1937: Level: intermediate
1939: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1940: @*/
1941: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1942: {
1950: if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
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;
1984: if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1985: if (len) {
1986: DM dm = dms[0];
1987: if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1988: (*dm->ops->createsuperdm)(dms, len, is, superdm);
1989: }
1990: return(0);
1991: }
1993: /*@C
1994: DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1995: corresponding to restrictions to pairs nested subdomains: each IS contains the global
1996: indices of the dofs of the corresponding subdomains. The inner subdomains conceptually
1997: define a nonoverlapping covering, while outer subdomains can overlap.
1998: The optional list of DMs define the DM for each subproblem.
2000: Not collective
2002: Input Parameter:
2003: . dm - the DM object
2005: Output Parameters:
2006: + len - The number of subproblems in the domain decomposition (or NULL if not requested)
2007: . namelist - The name for each subdomain (or NULL if not requested)
2008: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2009: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2010: - dmlist - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
2012: Level: intermediate
2014: Notes:
2015: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
2016: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
2017: and all of the arrays should be freed with PetscFree().
2019: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
2020: @*/
2021: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2022: {
2023: PetscErrorCode ierr;
2024: DMSubDomainHookLink link;
2025: PetscInt i,l;
2034: /*
2035: Is it a good idea to apply the following check across all impls?
2036: Perhaps some impls can have a well-defined decomposition before DMSetUp?
2037: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2038: */
2039: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2040: if (dm->ops->createdomaindecomposition) {
2041: (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
2042: /* copy subdomain hooks and context over to the subdomain DMs */
2043: if (dmlist && *dmlist) {
2044: for (i = 0; i < l; i++) {
2045: for (link=dm->subdomainhook; link; link=link->next) {
2046: if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
2047: }
2048: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2049: }
2050: }
2051: if (len) *len = l;
2052: }
2053: return(0);
2054: }
2056: /*@C
2057: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
2059: Not collective
2061: Input Parameters:
2062: + dm - the DM object
2063: . n - the number of subdomain scatters
2064: - subdms - the local subdomains
2066: Output Parameters:
2067: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2068: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2069: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2071: Notes:
2072: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2073: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2074: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2075: solution and residual data.
2077: Level: developer
2079: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2080: @*/
2081: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2082: {
2088: if (!dm->ops->createddscatters) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateDomainDecompositionScatters",((PetscObject)dm)->type_name);
2089: (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2090: return(0);
2091: }
2093: /*@
2094: DMRefine - Refines a DM object
2096: Collective on dm
2098: Input Parameters:
2099: + dm - the DM object
2100: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2102: Output Parameter:
2103: . dmf - the refined DM, or NULL
2105: Options Database Keys:
2106: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2108: Note: If no refinement was done, the return value is NULL
2110: Level: developer
2112: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2113: @*/
2114: PetscErrorCode DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2115: {
2116: PetscErrorCode ierr;
2117: DMRefineHookLink link;
2121: if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2122: PetscLogEventBegin(DM_Refine,dm,0,0,0);
2123: (*dm->ops->refine)(dm,comm,dmf);
2124: if (*dmf) {
2125: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2127: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);
2129: (*dmf)->ctx = dm->ctx;
2130: (*dmf)->leveldown = dm->leveldown;
2131: (*dmf)->levelup = dm->levelup + 1;
2133: DMSetMatType(*dmf,dm->mattype);
2134: for (link=dm->refinehook; link; link=link->next) {
2135: if (link->refinehook) {
2136: (*link->refinehook)(dm,*dmf,link->ctx);
2137: }
2138: }
2139: }
2140: PetscLogEventEnd(DM_Refine,dm,0,0,0);
2141: return(0);
2142: }
2144: /*@C
2145: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2147: Logically Collective
2149: Input Parameters:
2150: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2151: . refinehook - function to run when setting up a coarser level
2152: . interphook - function to run to update data on finer levels (once per SNESSolve())
2153: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2155: Calling sequence of refinehook:
2156: $ refinehook(DM coarse,DM fine,void *ctx);
2158: + coarse - coarse level DM
2159: . fine - fine level DM to interpolate problem to
2160: - ctx - optional user-defined function context
2162: Calling sequence for interphook:
2163: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2165: + coarse - coarse level DM
2166: . interp - matrix interpolating a coarse-level solution to the finer grid
2167: . fine - fine level DM to update
2168: - ctx - optional user-defined function context
2170: Level: advanced
2172: Notes:
2173: This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
2175: If this function is called multiple times, the hooks will be run in the order they are added.
2177: This function is currently not available from Fortran.
2179: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2180: @*/
2181: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2182: {
2183: PetscErrorCode ierr;
2184: DMRefineHookLink link,*p;
2188: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2189: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2190: }
2191: PetscNew(&link);
2192: link->refinehook = refinehook;
2193: link->interphook = interphook;
2194: link->ctx = ctx;
2195: link->next = NULL;
2196: *p = link;
2197: return(0);
2198: }
2200: /*@C
2201: DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
2203: Logically Collective
2205: Input Parameters:
2206: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2207: . refinehook - function to run when setting up a coarser level
2208: . interphook - function to run to update data on finer levels (once per SNESSolve())
2209: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2211: Level: advanced
2213: Notes:
2214: This function does nothing if the hook is not in the list.
2216: This function is currently not available from Fortran.
2218: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2219: @*/
2220: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2221: {
2222: PetscErrorCode ierr;
2223: DMRefineHookLink link,*p;
2227: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2228: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2229: link = *p;
2230: *p = link->next;
2231: PetscFree(link);
2232: break;
2233: }
2234: }
2235: return(0);
2236: }
2238: /*@
2239: DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
2241: Collective if any hooks are
2243: Input Parameters:
2244: + coarse - coarser DM to use as a base
2245: . interp - interpolation matrix, apply using MatInterpolate()
2246: - fine - finer DM to update
2248: Level: developer
2250: .seealso: DMRefineHookAdd(), MatInterpolate()
2251: @*/
2252: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2253: {
2254: PetscErrorCode ierr;
2255: DMRefineHookLink link;
2258: for (link=fine->refinehook; link; link=link->next) {
2259: if (link->interphook) {
2260: (*link->interphook)(coarse,interp,fine,link->ctx);
2261: }
2262: }
2263: return(0);
2264: }
2266: /*@
2267: DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2269: Collective on DM
2271: Input Parameters:
2272: + coarse - coarse DM
2273: . fine - fine DM
2274: . interp - (optional) the matrix computed by DMCreateInterpolation(). Implementations may not need this, but if it
2275: is available it can avoid some recomputation. If it is provided, MatInterpolate() will be used if
2276: the coarse DM does not have a specialized implementation.
2277: - coarseSol - solution on the coarse mesh
2279: Output Parameter:
2280: . fineSol - the interpolation of coarseSol to the fine mesh
2282: Level: developer
2284: Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2285: map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2286: out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2287: slope-limiting reconstruction.
2289: .seealso DMInterpolate(), DMCreateInterpolation()
2290: @*/
2291: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2292: {
2293: PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;
2302: PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2303: if (interpsol) {
2304: (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2305: } else if (interp) {
2306: MatInterpolate(interp, coarseSol, fineSol);
2307: } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2308: return(0);
2309: }
2311: /*@
2312: DMGetRefineLevel - Gets the number of refinements that have generated this DM.
2314: Not Collective
2316: Input Parameter:
2317: . dm - the DM object
2319: Output Parameter:
2320: . level - number of refinements
2322: Level: developer
2324: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2326: @*/
2327: PetscErrorCode DMGetRefineLevel(DM dm,PetscInt *level)
2328: {
2331: *level = dm->levelup;
2332: return(0);
2333: }
2335: /*@
2336: DMSetRefineLevel - Sets the number of refinements that have generated this DM.
2338: Not Collective
2340: Input Parameters:
2341: + dm - the DM object
2342: - level - number of refinements
2344: Level: advanced
2346: Notes:
2347: This value is used by PCMG to determine how many multigrid levels to use
2349: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2351: @*/
2352: PetscErrorCode DMSetRefineLevel(DM dm,PetscInt level)
2353: {
2356: dm->levelup = level;
2357: return(0);
2358: }
2360: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2361: {
2365: *tdm = dm->transformDM;
2366: return(0);
2367: }
2369: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2370: {
2374: *tv = dm->transform;
2375: return(0);
2376: }
2378: /*@
2379: DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors
2381: Input Parameter:
2382: . dm - The DM
2384: Output Parameter:
2385: . flg - PETSC_TRUE if a basis transformation should be done
2387: Level: developer
2389: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2390: @*/
2391: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2392: {
2393: Vec tv;
2399: DMGetBasisTransformVec_Internal(dm, &tv);
2400: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2401: return(0);
2402: }
2404: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2405: {
2406: PetscSection s, ts;
2407: PetscScalar *ta;
2408: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2412: DMGetCoordinateDim(dm, &cdim);
2413: DMGetLocalSection(dm, &s);
2414: PetscSectionGetChart(s, &pStart, &pEnd);
2415: PetscSectionGetNumFields(s, &Nf);
2416: DMClone(dm, &dm->transformDM);
2417: DMGetLocalSection(dm->transformDM, &ts);
2418: PetscSectionSetNumFields(ts, Nf);
2419: PetscSectionSetChart(ts, pStart, pEnd);
2420: for (f = 0; f < Nf; ++f) {
2421: PetscSectionGetFieldComponents(s, f, &Nc);
2422: /* We could start to label fields by their transformation properties */
2423: if (Nc != cdim) continue;
2424: for (p = pStart; p < pEnd; ++p) {
2425: PetscSectionGetFieldDof(s, p, f, &dof);
2426: if (!dof) continue;
2427: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2428: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2429: }
2430: }
2431: PetscSectionSetUp(ts);
2432: DMCreateLocalVector(dm->transformDM, &dm->transform);
2433: VecGetArray(dm->transform, &ta);
2434: for (p = pStart; p < pEnd; ++p) {
2435: for (f = 0; f < Nf; ++f) {
2436: PetscSectionGetFieldDof(ts, p, f, &dof);
2437: if (dof) {
2438: PetscReal x[3] = {0.0, 0.0, 0.0};
2439: PetscScalar *tva;
2440: const PetscScalar *A;
2442: /* TODO Get quadrature point for this dual basis vector for coordinate */
2443: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2444: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2445: PetscArraycpy(tva, A, PetscSqr(cdim));
2446: }
2447: }
2448: }
2449: VecRestoreArray(dm->transform, &ta);
2450: return(0);
2451: }
2453: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2454: {
2460: newdm->transformCtx = dm->transformCtx;
2461: newdm->transformSetUp = dm->transformSetUp;
2462: newdm->transformDestroy = NULL;
2463: newdm->transformGetMatrix = dm->transformGetMatrix;
2464: if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2465: return(0);
2466: }
2468: /*@C
2469: DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
2471: Logically Collective
2473: Input Parameters:
2474: + dm - the DM
2475: . beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2476: . endhook - function to run after DMGlobalToLocalEnd() has completed
2477: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2479: Calling sequence for beginhook:
2480: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2482: + dm - global DM
2483: . g - global vector
2484: . mode - mode
2485: . l - local vector
2486: - ctx - optional user-defined function context
2488: Calling sequence for endhook:
2489: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2491: + global - global DM
2492: - ctx - optional user-defined function context
2494: Level: advanced
2496: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2497: @*/
2498: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2499: {
2500: PetscErrorCode ierr;
2501: DMGlobalToLocalHookLink link,*p;
2505: for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2506: PetscNew(&link);
2507: link->beginhook = beginhook;
2508: link->endhook = endhook;
2509: link->ctx = ctx;
2510: link->next = NULL;
2511: *p = link;
2512: return(0);
2513: }
2515: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2516: {
2517: Mat cMat;
2518: Vec cVec;
2519: PetscSection section, cSec;
2520: PetscInt pStart, pEnd, p, dof;
2525: DMGetDefaultConstraints(dm,&cSec,&cMat);
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: PetscSectionGetChart(cSec,&pStart,&pEnd);
2535: for (p = pStart; p < pEnd; p++) {
2536: PetscSectionGetDof(cSec,p,&dof);
2537: if (dof) {
2538: PetscScalar *vals;
2539: VecGetValuesSection(cVec,cSec,p,&vals);
2540: VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2541: }
2542: }
2543: VecDestroy(&cVec);
2544: }
2545: return(0);
2546: }
2548: /*@
2549: DMGlobalToLocal - update local vectors from global vector
2551: Neighbor-wise Collective on dm
2553: Input Parameters:
2554: + dm - the DM object
2555: . g - the global vector
2556: . mode - INSERT_VALUES or ADD_VALUES
2557: - l - the local vector
2559: Notes:
2560: The communication involved in this update can be overlapped with computation by using
2561: DMGlobalToLocalBegin() and DMGlobalToLocalEnd().
2563: Level: beginner
2565: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2567: @*/
2568: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2569: {
2573: DMGlobalToLocalBegin(dm,g,mode,l);
2574: DMGlobalToLocalEnd(dm,g,mode,l);
2575: return(0);
2576: }
2578: /*@
2579: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2581: Neighbor-wise Collective on dm
2583: Input Parameters:
2584: + dm - the DM object
2585: . g - the global vector
2586: . mode - INSERT_VALUES or ADD_VALUES
2587: - l - the local vector
2589: Level: intermediate
2591: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2593: @*/
2594: PetscErrorCode DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2595: {
2596: PetscSF sf;
2597: PetscErrorCode ierr;
2598: DMGlobalToLocalHookLink link;
2602: for (link=dm->gtolhook; link; link=link->next) {
2603: if (link->beginhook) {
2604: (*link->beginhook)(dm,g,mode,l,link->ctx);
2605: }
2606: }
2607: DMGetSectionSF(dm, &sf);
2608: if (sf) {
2609: const PetscScalar *gArray;
2610: PetscScalar *lArray;
2611: PetscMemType lmtype,gmtype;
2613: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2614: VecGetArrayAndMemType(l, &lArray, &lmtype);
2615: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2616: PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2617: VecRestoreArrayAndMemType(l, &lArray);
2618: VecRestoreArrayReadAndMemType(g, &gArray);
2619: } else {
2620: if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2621: (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2622: }
2623: return(0);
2624: }
2626: /*@
2627: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2629: Neighbor-wise Collective on dm
2631: Input Parameters:
2632: + dm - the DM object
2633: . g - the global vector
2634: . mode - INSERT_VALUES or ADD_VALUES
2635: - l - the local vector
2637: Level: intermediate
2639: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2641: @*/
2642: PetscErrorCode DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2643: {
2644: PetscSF sf;
2645: PetscErrorCode ierr;
2646: const PetscScalar *gArray;
2647: PetscScalar *lArray;
2648: PetscBool transform;
2649: DMGlobalToLocalHookLink link;
2650: PetscMemType lmtype,gmtype;
2654: DMGetSectionSF(dm, &sf);
2655: DMHasBasisTransform(dm, &transform);
2656: if (sf) {
2657: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2659: VecGetArrayAndMemType(l, &lArray, &lmtype);
2660: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2661: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2662: VecRestoreArrayAndMemType(l, &lArray);
2663: VecRestoreArrayReadAndMemType(g, &gArray);
2664: if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2665: } else {
2666: if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2667: (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2668: }
2669: DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2670: for (link=dm->gtolhook; link; link=link->next) {
2671: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2672: }
2673: return(0);
2674: }
2676: /*@C
2677: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2679: Logically Collective
2681: Input Parameters:
2682: + dm - the DM
2683: . beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2684: . endhook - function to run after DMLocalToGlobalEnd() has completed
2685: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2687: Calling sequence for beginhook:
2688: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2690: + dm - global DM
2691: . l - local vector
2692: . mode - mode
2693: . g - global vector
2694: - ctx - optional user-defined function context
2696: Calling sequence for endhook:
2697: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2699: + global - global DM
2700: . l - local vector
2701: . mode - mode
2702: . g - global vector
2703: - ctx - optional user-defined function context
2705: Level: advanced
2707: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2708: @*/
2709: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2710: {
2711: PetscErrorCode ierr;
2712: DMLocalToGlobalHookLink link,*p;
2716: for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2717: PetscNew(&link);
2718: link->beginhook = beginhook;
2719: link->endhook = endhook;
2720: link->ctx = ctx;
2721: link->next = NULL;
2722: *p = link;
2723: return(0);
2724: }
2726: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2727: {
2728: Mat cMat;
2729: Vec cVec;
2730: PetscSection section, cSec;
2731: PetscInt pStart, pEnd, p, dof;
2736: DMGetDefaultConstraints(dm,&cSec,&cMat);
2737: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2738: PetscInt nRows;
2740: MatGetSize(cMat,&nRows,NULL);
2741: if (nRows <= 0) return(0);
2742: DMGetLocalSection(dm,§ion);
2743: MatCreateVecs(cMat,NULL,&cVec);
2744: PetscSectionGetChart(cSec,&pStart,&pEnd);
2745: for (p = pStart; p < pEnd; p++) {
2746: PetscSectionGetDof(cSec,p,&dof);
2747: if (dof) {
2748: PetscInt d;
2749: PetscScalar *vals;
2750: VecGetValuesSection(l,section,p,&vals);
2751: VecSetValuesSection(cVec,cSec,p,vals,mode);
2752: /* for this to be the true transpose, we have to zero the values that
2753: * we just extracted */
2754: for (d = 0; d < dof; d++) {
2755: vals[d] = 0.;
2756: }
2757: }
2758: }
2759: MatMultTransposeAdd(cMat,cVec,l,l);
2760: VecDestroy(&cVec);
2761: }
2762: return(0);
2763: }
2764: /*@
2765: DMLocalToGlobal - updates global vectors from local vectors
2767: Neighbor-wise Collective on dm
2769: Input Parameters:
2770: + dm - the DM object
2771: . l - the local vector
2772: . 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.
2773: - g - the global vector
2775: Notes:
2776: The communication involved in this update can be overlapped with computation by using
2777: DMLocalToGlobalBegin() and DMLocalToGlobalEnd().
2779: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2780: INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.
2782: Level: beginner
2784: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2786: @*/
2787: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2788: {
2792: DMLocalToGlobalBegin(dm,l,mode,g);
2793: DMLocalToGlobalEnd(dm,l,mode,g);
2794: return(0);
2795: }
2797: /*@
2798: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2800: Neighbor-wise Collective on dm
2802: Input Parameters:
2803: + dm - the DM object
2804: . l - the local vector
2805: . 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.
2806: - g - the global vector
2808: Notes:
2809: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2810: INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2812: Level: intermediate
2814: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2816: @*/
2817: PetscErrorCode DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2818: {
2819: PetscSF sf;
2820: PetscSection s, gs;
2821: DMLocalToGlobalHookLink link;
2822: Vec tmpl;
2823: const PetscScalar *lArray;
2824: PetscScalar *gArray;
2825: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2826: PetscErrorCode ierr;
2827: PetscMemType lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;
2831: for (link=dm->ltoghook; link; link=link->next) {
2832: if (link->beginhook) {
2833: (*link->beginhook)(dm,l,mode,g,link->ctx);
2834: }
2835: }
2836: DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2837: DMGetSectionSF(dm, &sf);
2838: DMGetLocalSection(dm, &s);
2839: switch (mode) {
2840: case INSERT_VALUES:
2841: case INSERT_ALL_VALUES:
2842: case INSERT_BC_VALUES:
2843: isInsert = PETSC_TRUE; break;
2844: case ADD_VALUES:
2845: case ADD_ALL_VALUES:
2846: case ADD_BC_VALUES:
2847: isInsert = PETSC_FALSE; break;
2848: default:
2849: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2850: }
2851: if ((sf && !isInsert) || (s && isInsert)) {
2852: DMHasBasisTransform(dm, &transform);
2853: if (transform) {
2854: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2855: VecCopy(l, tmpl);
2856: DMPlexLocalToGlobalBasis(dm, tmpl);
2857: VecGetArrayRead(tmpl, &lArray);
2858: } else if (isInsert) {
2859: VecGetArrayRead(l, &lArray);
2860: } else {
2861: VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2862: l_inplace = PETSC_TRUE;
2863: }
2864: if (s && isInsert) {
2865: VecGetArray(g, &gArray);
2866: } else {
2867: VecGetArrayAndMemType(g, &gArray, &gmtype);
2868: g_inplace = PETSC_TRUE;
2869: }
2870: if (sf && !isInsert) {
2871: PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2872: } else if (s && isInsert) {
2873: PetscInt gStart, pStart, pEnd, p;
2875: DMGetGlobalSection(dm, &gs);
2876: PetscSectionGetChart(s, &pStart, &pEnd);
2877: VecGetOwnershipRange(g, &gStart, NULL);
2878: for (p = pStart; p < pEnd; ++p) {
2879: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2881: PetscSectionGetDof(s, p, &dof);
2882: PetscSectionGetDof(gs, p, &gdof);
2883: PetscSectionGetConstraintDof(s, p, &cdof);
2884: PetscSectionGetConstraintDof(gs, p, &gcdof);
2885: PetscSectionGetOffset(s, p, &off);
2886: PetscSectionGetOffset(gs, p, &goff);
2887: /* Ignore off-process data and points with no global data */
2888: if (!gdof || goff < 0) continue;
2889: if (dof != gdof) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
2890: /* If no constraints are enforced in the global vector */
2891: if (!gcdof) {
2892: for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2893: /* If constraints are enforced in the global vector */
2894: } else if (cdof == gcdof) {
2895: const PetscInt *cdofs;
2896: PetscInt cind = 0;
2898: PetscSectionGetConstraintIndices(s, p, &cdofs);
2899: for (d = 0, e = 0; d < dof; ++d) {
2900: if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2901: gArray[goff-gStart+e++] = lArray[off+d];
2902: }
2903: } else SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
2904: }
2905: }
2906: if (g_inplace) {
2907: VecRestoreArrayAndMemType(g, &gArray);
2908: } else {
2909: VecRestoreArray(g, &gArray);
2910: }
2911: if (transform) {
2912: VecRestoreArrayRead(tmpl, &lArray);
2913: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2914: } else if (l_inplace) {
2915: VecRestoreArrayReadAndMemType(l, &lArray);
2916: } else {
2917: VecRestoreArrayRead(l, &lArray);
2918: }
2919: } else {
2920: if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2921: (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2922: }
2923: return(0);
2924: }
2926: /*@
2927: DMLocalToGlobalEnd - updates global vectors from local vectors
2929: Neighbor-wise Collective on dm
2931: Input Parameters:
2932: + dm - the DM object
2933: . l - the local vector
2934: . mode - INSERT_VALUES or ADD_VALUES
2935: - g - the global vector
2937: Level: intermediate
2939: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2941: @*/
2942: PetscErrorCode DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2943: {
2944: PetscSF sf;
2945: PetscSection s;
2946: DMLocalToGlobalHookLink link;
2947: PetscBool isInsert, transform;
2948: PetscErrorCode ierr;
2952: DMGetSectionSF(dm, &sf);
2953: DMGetLocalSection(dm, &s);
2954: switch (mode) {
2955: case INSERT_VALUES:
2956: case INSERT_ALL_VALUES:
2957: isInsert = PETSC_TRUE; break;
2958: case ADD_VALUES:
2959: case ADD_ALL_VALUES:
2960: isInsert = PETSC_FALSE; break;
2961: default:
2962: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2963: }
2964: if (sf && !isInsert) {
2965: const PetscScalar *lArray;
2966: PetscScalar *gArray;
2967: Vec tmpl;
2969: DMHasBasisTransform(dm, &transform);
2970: if (transform) {
2971: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2972: VecGetArrayRead(tmpl, &lArray);
2973: } else {
2974: VecGetArrayReadAndMemType(l, &lArray, NULL);
2975: }
2976: VecGetArrayAndMemType(g, &gArray, NULL);
2977: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2978: if (transform) {
2979: VecRestoreArrayRead(tmpl, &lArray);
2980: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2981: } else {
2982: VecRestoreArrayReadAndMemType(l, &lArray);
2983: }
2984: VecRestoreArrayAndMemType(g, &gArray);
2985: } else if (s && isInsert) {
2986: } else {
2987: if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2988: (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2989: }
2990: for (link=dm->ltoghook; link; link=link->next) {
2991: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2992: }
2993: return(0);
2994: }
2996: /*@
2997: DMLocalToLocalBegin - Maps from a local vector (including ghost points
2998: that contain irrelevant values) to another local vector where the ghost
2999: points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
3001: Neighbor-wise Collective on dm
3003: Input Parameters:
3004: + dm - the DM object
3005: . g - the original local vector
3006: - mode - one of INSERT_VALUES or ADD_VALUES
3008: Output Parameter:
3009: . l - the local vector with correct ghost values
3011: Level: intermediate
3013: Notes:
3014: The local vectors used here need not be the same as those
3015: obtained from DMCreateLocalVector(), BUT they
3016: must have the same parallel data layout; they could, for example, be
3017: obtained with VecDuplicate() from the DM originating vectors.
3019: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3021: @*/
3022: PetscErrorCode DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
3023: {
3024: PetscErrorCode ierr;
3028: if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
3029: (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3030: return(0);
3031: }
3033: /*@
3034: DMLocalToLocalEnd - Maps from a local vector (including ghost points
3035: that contain irrelevant values) to another local vector where the ghost
3036: points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
3038: Neighbor-wise Collective on dm
3040: Input Parameters:
3041: + da - the DM object
3042: . g - the original local vector
3043: - mode - one of INSERT_VALUES or ADD_VALUES
3045: Output Parameter:
3046: . l - the local vector with correct ghost values
3048: Level: intermediate
3050: Notes:
3051: The local vectors used here need not be the same as those
3052: obtained from DMCreateLocalVector(), BUT they
3053: must have the same parallel data layout; they could, for example, be
3054: obtained with VecDuplicate() from the DM originating vectors.
3056: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3058: @*/
3059: PetscErrorCode DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3060: {
3061: PetscErrorCode ierr;
3065: if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
3066: (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3067: return(0);
3068: }
3070: /*@
3071: DMCoarsen - Coarsens a DM object
3073: Collective on dm
3075: Input Parameters:
3076: + dm - the DM object
3077: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
3079: Output Parameter:
3080: . dmc - the coarsened DM
3082: Level: developer
3084: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3086: @*/
3087: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3088: {
3089: PetscErrorCode ierr;
3090: DMCoarsenHookLink link;
3094: if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
3095: PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3096: (*dm->ops->coarsen)(dm, comm, dmc);
3097: if (*dmc) {
3098: DMSetCoarseDM(dm,*dmc);
3099: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3100: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3101: (*dmc)->ctx = dm->ctx;
3102: (*dmc)->levelup = dm->levelup;
3103: (*dmc)->leveldown = dm->leveldown + 1;
3104: DMSetMatType(*dmc,dm->mattype);
3105: for (link=dm->coarsenhook; link; link=link->next) {
3106: if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3107: }
3108: }
3109: PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3110: if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3111: return(0);
3112: }
3114: /*@C
3115: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3117: Logically Collective
3119: Input Parameters:
3120: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3121: . coarsenhook - function to run when setting up a coarser level
3122: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3123: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3125: Calling sequence of coarsenhook:
3126: $ coarsenhook(DM fine,DM coarse,void *ctx);
3128: + fine - fine level DM
3129: . coarse - coarse level DM to restrict problem to
3130: - ctx - optional user-defined function context
3132: Calling sequence for restricthook:
3133: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3135: + fine - fine level DM
3136: . mrestrict - matrix restricting a fine-level solution to the coarse grid
3137: . rscale - scaling vector for restriction
3138: . inject - matrix restricting by injection
3139: . coarse - coarse level DM to update
3140: - ctx - optional user-defined function context
3142: Level: advanced
3144: Notes:
3145: This function is only needed if auxiliary data needs to be set up on coarse grids.
3147: If this function is called multiple times, the hooks will be run in the order they are added.
3149: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3150: extract the finest level information from its context (instead of from the SNES).
3152: This function is currently not available from Fortran.
3154: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3155: @*/
3156: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3157: {
3158: PetscErrorCode ierr;
3159: DMCoarsenHookLink link,*p;
3163: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3164: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3165: }
3166: PetscNew(&link);
3167: link->coarsenhook = coarsenhook;
3168: link->restricthook = restricthook;
3169: link->ctx = ctx;
3170: link->next = NULL;
3171: *p = link;
3172: return(0);
3173: }
3175: /*@C
3176: DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
3178: Logically Collective
3180: Input Parameters:
3181: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3182: . coarsenhook - function to run when setting up a coarser level
3183: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3184: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3186: Level: advanced
3188: Notes:
3189: This function does nothing if the hook is not in the list.
3191: This function is currently not available from Fortran.
3193: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3194: @*/
3195: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3196: {
3197: PetscErrorCode ierr;
3198: DMCoarsenHookLink link,*p;
3202: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3203: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3204: link = *p;
3205: *p = link->next;
3206: PetscFree(link);
3207: break;
3208: }
3209: }
3210: return(0);
3211: }
3213: /*@
3214: DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
3216: Collective if any hooks are
3218: Input Parameters:
3219: + fine - finer DM to use as a base
3220: . restrct - restriction matrix, apply using MatRestrict()
3221: . rscale - scaling vector for restriction
3222: . inject - injection matrix, also use MatRestrict()
3223: - coarse - coarser DM to update
3225: Level: developer
3227: .seealso: DMCoarsenHookAdd(), MatRestrict()
3228: @*/
3229: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3230: {
3231: PetscErrorCode ierr;
3232: DMCoarsenHookLink link;
3235: for (link=fine->coarsenhook; link; link=link->next) {
3236: if (link->restricthook) {
3237: (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3238: }
3239: }
3240: return(0);
3241: }
3243: /*@C
3244: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3246: Logically Collective on global
3248: Input Parameters:
3249: + global - global DM
3250: . ddhook - function to run to pass data to the decomposition DM upon its creation
3251: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3252: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3254: Calling sequence for ddhook:
3255: $ ddhook(DM global,DM block,void *ctx)
3257: + global - global DM
3258: . block - block DM
3259: - ctx - optional user-defined function context
3261: Calling sequence for restricthook:
3262: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3264: + global - global DM
3265: . out - scatter to the outer (with ghost and overlap points) block vector
3266: . in - scatter to block vector values only owned locally
3267: . block - block DM
3268: - ctx - optional user-defined function context
3270: Level: advanced
3272: Notes:
3273: This function is only needed if auxiliary data needs to be set up on subdomain DMs.
3275: If this function is called multiple times, the hooks will be run in the order they are added.
3277: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3278: extract the global information from its context (instead of from the SNES).
3280: This function is currently not available from Fortran.
3282: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3283: @*/
3284: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3285: {
3286: PetscErrorCode ierr;
3287: DMSubDomainHookLink link,*p;
3291: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3292: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3293: }
3294: PetscNew(&link);
3295: link->restricthook = restricthook;
3296: link->ddhook = ddhook;
3297: link->ctx = ctx;
3298: link->next = NULL;
3299: *p = link;
3300: return(0);
3301: }
3303: /*@C
3304: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3306: Logically Collective
3308: Input Parameters:
3309: + global - global DM
3310: . ddhook - function to run to pass data to the decomposition DM upon its creation
3311: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3312: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3314: Level: advanced
3316: Notes:
3318: This function is currently not available from Fortran.
3320: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3321: @*/
3322: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3323: {
3324: PetscErrorCode ierr;
3325: DMSubDomainHookLink link,*p;
3329: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3330: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3331: link = *p;
3332: *p = link->next;
3333: PetscFree(link);
3334: break;
3335: }
3336: }
3337: return(0);
3338: }
3340: /*@
3341: DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
3343: Collective if any hooks are
3345: Input Parameters:
3346: + fine - finer DM to use as a base
3347: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3348: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3349: - coarse - coarer DM to update
3351: Level: developer
3353: .seealso: DMCoarsenHookAdd(), MatRestrict()
3354: @*/
3355: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3356: {
3357: PetscErrorCode ierr;
3358: DMSubDomainHookLink link;
3361: for (link=global->subdomainhook; link; link=link->next) {
3362: if (link->restricthook) {
3363: (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3364: }
3365: }
3366: return(0);
3367: }
3369: /*@
3370: DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
3372: Not Collective
3374: Input Parameter:
3375: . dm - the DM object
3377: Output Parameter:
3378: . level - number of coarsenings
3380: Level: developer
3382: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3384: @*/
3385: PetscErrorCode DMGetCoarsenLevel(DM dm,PetscInt *level)
3386: {
3390: *level = dm->leveldown;
3391: return(0);
3392: }
3394: /*@
3395: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
3397: Not Collective
3399: Input Parameters:
3400: + dm - the DM object
3401: - level - number of coarsenings
3403: Level: developer
3405: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3406: @*/
3407: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3408: {
3411: dm->leveldown = level;
3412: return(0);
3413: }
3415: /*@C
3416: DMRefineHierarchy - Refines a DM object, all levels at once
3418: Collective on dm
3420: Input Parameters:
3421: + dm - the DM object
3422: - nlevels - the number of levels of refinement
3424: Output Parameter:
3425: . dmf - the refined DM hierarchy
3427: Level: developer
3429: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3431: @*/
3432: PetscErrorCode DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3433: {
3438: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3439: if (nlevels == 0) return(0);
3441: if (dm->ops->refinehierarchy) {
3442: (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3443: } else if (dm->ops->refine) {
3444: PetscInt i;
3446: DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3447: for (i=1; i<nlevels; i++) {
3448: DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3449: }
3450: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3451: return(0);
3452: }
3454: /*@C
3455: DMCoarsenHierarchy - Coarsens a DM object, all levels at once
3457: Collective on dm
3459: Input Parameters:
3460: + dm - the DM object
3461: - nlevels - the number of levels of coarsening
3463: Output Parameter:
3464: . dmc - the coarsened DM hierarchy
3466: Level: developer
3468: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3470: @*/
3471: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3472: {
3477: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3478: if (nlevels == 0) return(0);
3480: if (dm->ops->coarsenhierarchy) {
3481: (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3482: } else if (dm->ops->coarsen) {
3483: PetscInt i;
3485: DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3486: for (i=1; i<nlevels; i++) {
3487: DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3488: }
3489: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3490: return(0);
3491: }
3493: /*@C
3494: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
3496: Not Collective
3498: Input Parameters:
3499: + dm - the DM object
3500: - destroy - the destroy function
3502: Level: intermediate
3504: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3506: @*/
3507: PetscErrorCode DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3508: {
3511: dm->ctxdestroy = destroy;
3512: return(0);
3513: }
3515: /*@
3516: DMSetApplicationContext - Set a user context into a DM object
3518: Not Collective
3520: Input Parameters:
3521: + dm - the DM object
3522: - ctx - the user context
3524: Level: intermediate
3526: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3528: @*/
3529: PetscErrorCode DMSetApplicationContext(DM dm,void *ctx)
3530: {
3533: dm->ctx = ctx;
3534: return(0);
3535: }
3537: /*@
3538: DMGetApplicationContext - Gets a user context from a DM object
3540: Not Collective
3542: Input Parameter:
3543: . dm - the DM object
3545: Output Parameter:
3546: . ctx - the user context
3548: Level: intermediate
3550: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3552: @*/
3553: PetscErrorCode DMGetApplicationContext(DM dm,void *ctx)
3554: {
3557: *(void**)ctx = dm->ctx;
3558: return(0);
3559: }
3561: /*@C
3562: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3564: Logically Collective on dm
3566: Input Parameters:
3567: + dm - the DM object
3568: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3570: Level: intermediate
3572: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3573: DMSetJacobian()
3575: @*/
3576: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3577: {
3580: dm->ops->computevariablebounds = f;
3581: return(0);
3582: }
3584: /*@
3585: DMHasVariableBounds - does the DM object have a variable bounds function?
3587: Not Collective
3589: Input Parameter:
3590: . dm - the DM object to destroy
3592: Output Parameter:
3593: . flg - PETSC_TRUE if the variable bounds function exists
3595: Level: developer
3597: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3599: @*/
3600: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3601: {
3605: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3606: return(0);
3607: }
3609: /*@C
3610: DMComputeVariableBounds - compute variable bounds used by SNESVI.
3612: Logically Collective on dm
3614: Input Parameter:
3615: . dm - the DM object
3617: Output parameters:
3618: + xl - lower bound
3619: - xu - upper bound
3621: Level: advanced
3623: Notes:
3624: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3626: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3628: @*/
3629: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3630: {
3637: if (!dm->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeVariableBounds",((PetscObject)dm)->type_name);
3638: (*dm->ops->computevariablebounds)(dm, xl,xu);
3639: return(0);
3640: }
3642: /*@
3643: DMHasColoring - does the DM object have a method of providing a coloring?
3645: Not Collective
3647: Input Parameter:
3648: . dm - the DM object
3650: Output Parameter:
3651: . flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3653: Level: developer
3655: .seealso DMCreateColoring()
3657: @*/
3658: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3659: {
3663: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3664: return(0);
3665: }
3667: /*@
3668: DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3670: Not Collective
3672: Input Parameter:
3673: . dm - the DM object
3675: Output Parameter:
3676: . flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3678: Level: developer
3680: .seealso DMCreateRestriction()
3682: @*/
3683: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3684: {
3688: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3689: return(0);
3690: }
3692: /*@
3693: DMHasCreateInjection - does the DM object have a method of providing an injection?
3695: Not Collective
3697: Input Parameter:
3698: . dm - the DM object
3700: Output Parameter:
3701: . flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3703: Level: developer
3705: .seealso DMCreateInjection()
3707: @*/
3708: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3709: {
3715: if (dm->ops->hascreateinjection) {
3716: (*dm->ops->hascreateinjection)(dm,flg);
3717: } else {
3718: *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3719: }
3720: return(0);
3721: }
3723: PetscFunctionList DMList = NULL;
3724: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3726: /*@C
3727: DMSetType - Builds a DM, for a particular DM implementation.
3729: Collective on dm
3731: Input Parameters:
3732: + dm - The DM object
3733: - method - The name of the DM type
3735: Options Database Key:
3736: . -dm_type <type> - Sets the DM type; use -help for a list of available types
3738: Notes:
3739: See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3741: Level: intermediate
3743: .seealso: DMGetType(), DMCreate()
3744: @*/
3745: PetscErrorCode DMSetType(DM dm, DMType method)
3746: {
3747: PetscErrorCode (*r)(DM);
3748: PetscBool match;
3753: PetscObjectTypeCompare((PetscObject) dm, method, &match);
3754: if (match) return(0);
3756: DMRegisterAll();
3757: PetscFunctionListFind(DMList,method,&r);
3758: if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3760: if (dm->ops->destroy) {
3761: (*dm->ops->destroy)(dm);
3762: }
3763: PetscMemzero(dm->ops,sizeof(*dm->ops));
3764: PetscObjectChangeTypeName((PetscObject)dm,method);
3765: (*r)(dm);
3766: return(0);
3767: }
3769: /*@C
3770: DMGetType - Gets the DM type name (as a string) from the DM.
3772: Not Collective
3774: Input Parameter:
3775: . dm - The DM
3777: Output Parameter:
3778: . type - The DM type name
3780: Level: intermediate
3782: .seealso: DMSetType(), DMCreate()
3783: @*/
3784: PetscErrorCode DMGetType(DM dm, DMType *type)
3785: {
3791: DMRegisterAll();
3792: *type = ((PetscObject)dm)->type_name;
3793: return(0);
3794: }
3796: /*@C
3797: DMConvert - Converts a DM to another DM, either of the same or different type.
3799: Collective on dm
3801: Input Parameters:
3802: + dm - the DM
3803: - newtype - new DM type (use "same" for the same type)
3805: Output Parameter:
3806: . M - pointer to new DM
3808: Notes:
3809: Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3810: the MPI communicator of the generated DM is always the same as the communicator
3811: of the input DM.
3813: Level: intermediate
3815: .seealso: DMCreate()
3816: @*/
3817: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3818: {
3819: DM B;
3820: char convname[256];
3821: PetscBool sametype/*, issame */;
3828: PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3829: /* PetscStrcmp(newtype, "same", &issame); */
3830: if (sametype) {
3831: *M = dm;
3832: PetscObjectReference((PetscObject) dm);
3833: return(0);
3834: } else {
3835: PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3837: /*
3838: Order of precedence:
3839: 1) See if a specialized converter is known to the current DM.
3840: 2) See if a specialized converter is known to the desired DM class.
3841: 3) See if a good general converter is registered for the desired class
3842: 4) See if a good general converter is known for the current matrix.
3843: 5) Use a really basic converter.
3844: */
3846: /* 1) See if a specialized converter is known to the current DM and the desired class */
3847: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3848: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3849: PetscStrlcat(convname,"_",sizeof(convname));
3850: PetscStrlcat(convname,newtype,sizeof(convname));
3851: PetscStrlcat(convname,"_C",sizeof(convname));
3852: PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3853: if (conv) goto foundconv;
3855: /* 2) See if a specialized converter is known to the desired DM class. */
3856: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3857: DMSetType(B, newtype);
3858: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3859: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3860: PetscStrlcat(convname,"_",sizeof(convname));
3861: PetscStrlcat(convname,newtype,sizeof(convname));
3862: PetscStrlcat(convname,"_C",sizeof(convname));
3863: PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3864: if (conv) {
3865: DMDestroy(&B);
3866: goto foundconv;
3867: }
3869: #if 0
3870: /* 3) See if a good general converter is registered for the desired class */
3871: conv = B->ops->convertfrom;
3872: DMDestroy(&B);
3873: if (conv) goto foundconv;
3875: /* 4) See if a good general converter is known for the current matrix */
3876: if (dm->ops->convert) {
3877: conv = dm->ops->convert;
3878: }
3879: if (conv) goto foundconv;
3880: #endif
3882: /* 5) Use a really basic converter. */
3883: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3885: foundconv:
3886: PetscLogEventBegin(DM_Convert,dm,0,0,0);
3887: (*conv)(dm,newtype,M);
3888: /* Things that are independent of DM type: We should consult DMClone() here */
3889: {
3890: PetscBool isper;
3891: const PetscReal *maxCell, *L;
3892: const DMBoundaryType *bd;
3893: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3894: DMSetPeriodicity(*M, isper, maxCell, L, bd);
3895: (*M)->prealloc_only = dm->prealloc_only;
3896: PetscFree((*M)->vectype);
3897: PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3898: PetscFree((*M)->mattype);
3899: PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3900: }
3901: PetscLogEventEnd(DM_Convert,dm,0,0,0);
3902: }
3903: PetscObjectStateIncrease((PetscObject) *M);
3904: return(0);
3905: }
3907: /*--------------------------------------------------------------------------------------------------------------------*/
3909: /*@C
3910: DMRegister - Adds a new DM component implementation
3912: Not Collective
3914: Input Parameters:
3915: + name - The name of a new user-defined creation routine
3916: - create_func - The creation routine itself
3918: Notes:
3919: DMRegister() may be called multiple times to add several user-defined DMs
3921: Sample usage:
3922: .vb
3923: DMRegister("my_da", MyDMCreate);
3924: .ve
3926: Then, your DM type can be chosen with the procedural interface via
3927: .vb
3928: DMCreate(MPI_Comm, DM *);
3929: DMSetType(DM,"my_da");
3930: .ve
3931: or at runtime via the option
3932: .vb
3933: -da_type my_da
3934: .ve
3936: Level: advanced
3938: .seealso: DMRegisterAll(), DMRegisterDestroy()
3940: @*/
3941: PetscErrorCode DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3942: {
3946: DMInitializePackage();
3947: PetscFunctionListAdd(&DMList,sname,function);
3948: return(0);
3949: }
3951: /*@C
3952: DMLoad - Loads a DM that has been stored in binary with DMView().
3954: Collective on viewer
3956: Input Parameters:
3957: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3958: some related function before a call to DMLoad().
3959: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3960: HDF5 file viewer, obtained from PetscViewerHDF5Open()
3962: Level: intermediate
3964: Notes:
3965: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3967: Notes for advanced users:
3968: Most users should not need to know the details of the binary storage
3969: format, since DMLoad() and DMView() completely hide these details.
3970: But for anyone who's interested, the standard binary matrix storage
3971: format is
3972: .vb
3973: has not yet been determined
3974: .ve
3976: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3977: @*/
3978: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
3979: {
3980: PetscBool isbinary, ishdf5;
3986: PetscViewerCheckReadable(viewer);
3987: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3988: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3989: PetscLogEventBegin(DM_Load,viewer,0,0,0);
3990: if (isbinary) {
3991: PetscInt classid;
3992: char type[256];
3994: PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3995: if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3996: PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3997: DMSetType(newdm, type);
3998: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3999: } else if (ishdf5) {
4000: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
4001: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4002: PetscLogEventEnd(DM_Load,viewer,0,0,0);
4003: return(0);
4004: }
4006: /*@
4007: DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
4009: Not collective
4011: Input Parameter:
4012: . dm - the DM
4014: Output Parameters:
4015: + lmin - local minimum coordinates (length coord dim, optional)
4016: - lmax - local maximim coordinates (length coord dim, optional)
4018: Level: beginner
4020: Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
4022: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
4023: @*/
4024: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
4025: {
4026: Vec coords = NULL;
4027: PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
4028: PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
4029: const PetscScalar *local_coords;
4030: PetscInt N, Ni;
4031: PetscInt cdim, i, j;
4032: PetscErrorCode ierr;
4036: DMGetCoordinateDim(dm, &cdim);
4037: DMGetCoordinates(dm, &coords);
4038: if (coords) {
4039: VecGetArrayRead(coords, &local_coords);
4040: VecGetLocalSize(coords, &N);
4041: Ni = N/cdim;
4042: for (i = 0; i < Ni; ++i) {
4043: for (j = 0; j < 3; ++j) {
4044: min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4045: max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4046: }
4047: }
4048: VecRestoreArrayRead(coords, &local_coords);
4049: } else {
4050: PetscBool isda;
4052: PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4053: if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4054: }
4055: if (lmin) {PetscArraycpy(lmin, min, cdim);}
4056: if (lmax) {PetscArraycpy(lmax, max, cdim);}
4057: return(0);
4058: }
4060: /*@
4061: DMGetBoundingBox - Returns the global bounding box for the DM.
4063: Collective
4065: Input Parameter:
4066: . dm - the DM
4068: Output Parameters:
4069: + gmin - global minimum coordinates (length coord dim, optional)
4070: - gmax - global maximim coordinates (length coord dim, optional)
4072: Level: beginner
4074: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4075: @*/
4076: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4077: {
4078: PetscReal lmin[3], lmax[3];
4079: PetscInt cdim;
4080: PetscMPIInt count;
4085: DMGetCoordinateDim(dm, &cdim);
4086: PetscMPIIntCast(cdim, &count);
4087: DMGetLocalBoundingBox(dm, lmin, lmax);
4088: if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4089: if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4090: return(0);
4091: }
4093: /******************************** FEM Support **********************************/
4095: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4096: {
4097: PetscInt f;
4101: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4102: for (f = 0; f < len; ++f) {
4103: PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
4104: }
4105: return(0);
4106: }
4108: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4109: {
4110: PetscInt f, g;
4114: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4115: for (f = 0; f < rows; ++f) {
4116: PetscPrintf(PETSC_COMM_SELF, " |");
4117: for (g = 0; g < cols; ++g) {
4118: PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4119: }
4120: PetscPrintf(PETSC_COMM_SELF, " |\n");
4121: }
4122: return(0);
4123: }
4125: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4126: {
4127: PetscInt localSize, bs;
4128: PetscMPIInt size;
4129: Vec x, xglob;
4130: const PetscScalar *xarray;
4131: PetscErrorCode ierr;
4134: MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4135: VecDuplicate(X, &x);
4136: VecCopy(X, x);
4137: VecChop(x, tol);
4138: PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4139: if (size > 1) {
4140: VecGetLocalSize(x,&localSize);
4141: VecGetArrayRead(x,&xarray);
4142: VecGetBlockSize(x,&bs);
4143: VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4144: } else {
4145: xglob = x;
4146: }
4147: VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4148: if (size > 1) {
4149: VecDestroy(&xglob);
4150: VecRestoreArrayRead(x,&xarray);
4151: }
4152: VecDestroy(&x);
4153: return(0);
4154: }
4156: /*@
4157: DMGetSection - Get the PetscSection encoding the local data layout for the DM. This is equivalent to DMGetLocalSection(). Deprecated in v3.12
4159: Input Parameter:
4160: . dm - The DM
4162: Output Parameter:
4163: . section - The PetscSection
4165: Options Database Keys:
4166: . -dm_petscsection_view - View the Section created by the DM
4168: Level: advanced
4170: Notes:
4171: Use DMGetLocalSection() in new code.
4173: This gets a borrowed reference, so the user should not destroy this PetscSection.
4175: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4176: @*/
4177: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4178: {
4182: DMGetLocalSection(dm,section);
4183: return(0);
4184: }
4186: /*@
4187: DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
4189: Input Parameter:
4190: . dm - The DM
4192: Output Parameter:
4193: . section - The PetscSection
4195: Options Database Keys:
4196: . -dm_petscsection_view - View the Section created by the DM
4198: Level: intermediate
4200: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4202: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4203: @*/
4204: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4205: {
4211: if (!dm->localSection && dm->ops->createlocalsection) {
4212: PetscInt d;
4214: if (dm->setfromoptionscalled) {
4215: PetscObject obj = (PetscObject) dm;
4216: PetscViewer viewer;
4217: PetscViewerFormat format;
4218: PetscBool flg;
4220: PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4221: if (flg) {PetscViewerPushFormat(viewer, format);}
4222: for (d = 0; d < dm->Nds; ++d) {
4223: PetscDSSetFromOptions(dm->probs[d].ds);
4224: if (flg) {PetscDSView(dm->probs[d].ds, viewer);}
4225: }
4226: if (flg) {
4227: PetscViewerFlush(viewer);
4228: PetscViewerPopFormat(viewer);
4229: PetscViewerDestroy(&viewer);
4230: }
4231: }
4232: (*dm->ops->createlocalsection)(dm);
4233: if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4234: }
4235: *section = dm->localSection;
4236: return(0);
4237: }
4239: /*@
4240: DMSetSection - Set the PetscSection encoding the local data layout for the DM. This is equivalent to DMSetLocalSection(). Deprecated in v3.12
4242: Input Parameters:
4243: + dm - The DM
4244: - section - The PetscSection
4246: Level: advanced
4248: Notes:
4249: Use DMSetLocalSection() in new code.
4251: Any existing Section will be destroyed
4253: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4254: @*/
4255: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4256: {
4260: DMSetLocalSection(dm,section);
4261: return(0);
4262: }
4264: /*@
4265: DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
4267: Input Parameters:
4268: + dm - The DM
4269: - section - The PetscSection
4271: Level: intermediate
4273: Note: Any existing Section will be destroyed
4275: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4276: @*/
4277: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4278: {
4279: PetscInt numFields = 0;
4280: PetscInt f;
4286: PetscObjectReference((PetscObject)section);
4287: PetscSectionDestroy(&dm->localSection);
4288: dm->localSection = section;
4289: if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4290: if (numFields) {
4291: DMSetNumFields(dm, numFields);
4292: for (f = 0; f < numFields; ++f) {
4293: PetscObject disc;
4294: const char *name;
4296: PetscSectionGetFieldName(dm->localSection, f, &name);
4297: DMGetField(dm, f, NULL, &disc);
4298: PetscObjectSetName(disc, name);
4299: }
4300: }
4301: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4302: PetscSectionDestroy(&dm->globalSection);
4303: return(0);
4304: }
4306: /*@
4307: DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4309: not collective
4311: Input Parameter:
4312: . dm - The DM
4314: Output Parameters:
4315: + 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.
4316: - 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.
4318: Level: advanced
4320: Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
4322: .seealso: DMSetDefaultConstraints()
4323: @*/
4324: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4325: {
4330: if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4331: if (section) {*section = dm->defaultConstraintSection;}
4332: if (mat) {*mat = dm->defaultConstraintMat;}
4333: return(0);
4334: }
4336: /*@
4337: DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4339: If a constraint matrix is specified, then it is applied during DMGlobalToLocalEnd() when mode is INSERT_VALUES, INSERT_BC_VALUES, or INSERT_ALL_VALUES. Without a constraint matrix, the local vector l returned by DMGlobalToLocalEnd() contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l, l[s[i]] = c[i], where the scatter s is defined by the PetscSection returned by DMGetDefaultConstraintMatrix().
4341: 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.
4343: collective on dm
4345: Input Parameters:
4346: + dm - The DM
4347: + 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).
4348: - 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).
4350: Level: advanced
4352: Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
4354: .seealso: DMGetDefaultConstraints()
4355: @*/
4356: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4357: {
4358: PetscMPIInt result;
4363: if (section) {
4365: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4366: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4367: }
4368: if (mat) {
4370: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4371: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4372: }
4373: PetscObjectReference((PetscObject)section);
4374: PetscSectionDestroy(&dm->defaultConstraintSection);
4375: dm->defaultConstraintSection = section;
4376: PetscObjectReference((PetscObject)mat);
4377: MatDestroy(&dm->defaultConstraintMat);
4378: dm->defaultConstraintMat = mat;
4379: return(0);
4380: }
4382: #if defined(PETSC_USE_DEBUG)
4383: /*
4384: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4386: Input Parameters:
4387: + dm - The DM
4388: . localSection - PetscSection describing the local data layout
4389: - globalSection - PetscSection describing the global data layout
4391: Level: intermediate
4393: .seealso: DMGetSectionSF(), DMSetSectionSF()
4394: */
4395: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4396: {
4397: MPI_Comm comm;
4398: PetscLayout layout;
4399: const PetscInt *ranges;
4400: PetscInt pStart, pEnd, p, nroots;
4401: PetscMPIInt size, rank;
4402: PetscBool valid = PETSC_TRUE, gvalid;
4403: PetscErrorCode ierr;
4406: PetscObjectGetComm((PetscObject)dm,&comm);
4408: MPI_Comm_size(comm, &size);
4409: MPI_Comm_rank(comm, &rank);
4410: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4411: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4412: PetscLayoutCreate(comm, &layout);
4413: PetscLayoutSetBlockSize(layout, 1);
4414: PetscLayoutSetLocalSize(layout, nroots);
4415: PetscLayoutSetUp(layout);
4416: PetscLayoutGetRanges(layout, &ranges);
4417: for (p = pStart; p < pEnd; ++p) {
4418: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4420: PetscSectionGetDof(localSection, p, &dof);
4421: PetscSectionGetOffset(localSection, p, &off);
4422: PetscSectionGetConstraintDof(localSection, p, &cdof);
4423: PetscSectionGetDof(globalSection, p, &gdof);
4424: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4425: PetscSectionGetOffset(globalSection, p, &goff);
4426: if (!gdof) continue; /* Censored point */
4427: 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;}
4428: 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;}
4429: if (gdof < 0) {
4430: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4431: for (d = 0; d < gsize; ++d) {
4432: PetscInt offset = -(goff+1) + d, r;
4434: PetscFindInt(offset,size+1,ranges,&r);
4435: if (r < 0) r = -(r+2);
4436: 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;}
4437: }
4438: }
4439: }
4440: PetscLayoutDestroy(&layout);
4441: PetscSynchronizedFlush(comm, NULL);
4442: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4443: if (!gvalid) {
4444: DMView(dm, NULL);
4445: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4446: }
4447: return(0);
4448: }
4449: #endif
4451: /*@
4452: DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4454: Collective on dm
4456: Input Parameter:
4457: . dm - The DM
4459: Output Parameter:
4460: . section - The PetscSection
4462: Level: intermediate
4464: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4466: .seealso: DMSetLocalSection(), DMGetLocalSection()
4467: @*/
4468: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4469: {
4475: if (!dm->globalSection) {
4476: PetscSection s;
4478: DMGetLocalSection(dm, &s);
4479: if (!s) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4480: if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4481: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4482: PetscLayoutDestroy(&dm->map);
4483: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4484: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4485: }
4486: *section = dm->globalSection;
4487: return(0);
4488: }
4490: /*@
4491: DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4493: Input Parameters:
4494: + dm - The DM
4495: - section - The PetscSection, or NULL
4497: Level: intermediate
4499: Note: Any existing Section will be destroyed
4501: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4502: @*/
4503: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4504: {
4510: PetscObjectReference((PetscObject)section);
4511: PetscSectionDestroy(&dm->globalSection);
4512: dm->globalSection = section;
4513: #if defined(PETSC_USE_DEBUG)
4514: if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4515: #endif
4516: return(0);
4517: }
4519: /*@
4520: DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4521: it is created from the default PetscSection layouts in the DM.
4523: Input Parameter:
4524: . dm - The DM
4526: Output Parameter:
4527: . sf - The PetscSF
4529: Level: intermediate
4531: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4533: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4534: @*/
4535: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4536: {
4537: PetscInt nroots;
4543: if (!dm->sectionSF) {
4544: PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4545: }
4546: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4547: if (nroots < 0) {
4548: PetscSection section, gSection;
4550: DMGetLocalSection(dm, §ion);
4551: if (section) {
4552: DMGetGlobalSection(dm, &gSection);
4553: DMCreateSectionSF(dm, section, gSection);
4554: } else {
4555: *sf = NULL;
4556: return(0);
4557: }
4558: }
4559: *sf = dm->sectionSF;
4560: return(0);
4561: }
4563: /*@
4564: DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4566: Input Parameters:
4567: + dm - The DM
4568: - sf - The PetscSF
4570: Level: intermediate
4572: Note: Any previous SF is destroyed
4574: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4575: @*/
4576: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4577: {
4583: PetscObjectReference((PetscObject) sf);
4584: PetscSFDestroy(&dm->sectionSF);
4585: dm->sectionSF = sf;
4586: return(0);
4587: }
4589: /*@C
4590: DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4591: describing the data layout.
4593: Input Parameters:
4594: + dm - The DM
4595: . localSection - PetscSection describing the local data layout
4596: - globalSection - PetscSection describing the global data layout
4598: Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4600: Level: developer
4602: Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4603: directly into the DM, perhaps this function should not take the local and global sections as
4604: input and should just obtain them from the DM?
4606: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4607: @*/
4608: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4609: {
4614: PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4615: return(0);
4616: }
4618: /*@
4619: DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4621: Input Parameter:
4622: . dm - The DM
4624: Output Parameter:
4625: . sf - The PetscSF
4627: Level: intermediate
4629: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4631: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4632: @*/
4633: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4634: {
4638: *sf = dm->sf;
4639: return(0);
4640: }
4642: /*@
4643: DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4645: Input Parameters:
4646: + dm - The DM
4647: - sf - The PetscSF
4649: Level: intermediate
4651: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4652: @*/
4653: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4654: {
4660: PetscObjectReference((PetscObject) sf);
4661: PetscSFDestroy(&dm->sf);
4662: dm->sf = sf;
4663: return(0);
4664: }
4666: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4667: {
4668: PetscClassId id;
4672: PetscObjectGetClassId(disc, &id);
4673: if (id == PETSCFE_CLASSID) {
4674: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4675: } else if (id == PETSCFV_CLASSID) {
4676: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4677: } else {
4678: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4679: }
4680: return(0);
4681: }
4683: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4684: {
4685: RegionField *tmpr;
4686: PetscInt Nf = dm->Nf, f;
4690: if (Nf >= NfNew) return(0);
4691: PetscMalloc1(NfNew, &tmpr);
4692: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4693: for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4694: PetscFree(dm->fields);
4695: dm->Nf = NfNew;
4696: dm->fields = tmpr;
4697: return(0);
4698: }
4700: /*@
4701: DMClearFields - Remove all fields from the DM
4703: Logically collective on dm
4705: Input Parameter:
4706: . dm - The DM
4708: Level: intermediate
4710: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4711: @*/
4712: PetscErrorCode DMClearFields(DM dm)
4713: {
4714: PetscInt f;
4719: for (f = 0; f < dm->Nf; ++f) {
4720: PetscObjectDestroy(&dm->fields[f].disc);
4721: DMLabelDestroy(&dm->fields[f].label);
4722: }
4723: PetscFree(dm->fields);
4724: dm->fields = NULL;
4725: dm->Nf = 0;
4726: return(0);
4727: }
4729: /*@
4730: DMGetNumFields - Get the number of fields in the DM
4732: Not collective
4734: Input Parameter:
4735: . dm - The DM
4737: Output Parameter:
4738: . Nf - The number of fields
4740: Level: intermediate
4742: .seealso: DMSetNumFields(), DMSetField()
4743: @*/
4744: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4745: {
4749: *numFields = dm->Nf;
4750: return(0);
4751: }
4753: /*@
4754: DMSetNumFields - Set the number of fields in the DM
4756: Logically collective on dm
4758: Input Parameters:
4759: + dm - The DM
4760: - Nf - The number of fields
4762: Level: intermediate
4764: .seealso: DMGetNumFields(), DMSetField()
4765: @*/
4766: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4767: {
4768: PetscInt Nf, f;
4773: DMGetNumFields(dm, &Nf);
4774: for (f = Nf; f < numFields; ++f) {
4775: PetscContainer obj;
4777: PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4778: DMAddField(dm, NULL, (PetscObject) obj);
4779: PetscContainerDestroy(&obj);
4780: }
4781: return(0);
4782: }
4784: /*@
4785: DMGetField - Return the discretization object for a given DM field
4787: Not collective
4789: Input Parameters:
4790: + dm - The DM
4791: - f - The field number
4793: Output Parameters:
4794: + label - The label indicating the support of the field, or NULL for the entire mesh
4795: - field - The discretization object
4797: Level: intermediate
4799: .seealso: DMAddField(), DMSetField()
4800: @*/
4801: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4802: {
4806: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, dm->Nf);
4807: if (label) *label = dm->fields[f].label;
4808: if (field) *field = dm->fields[f].disc;
4809: return(0);
4810: }
4812: /* Does not clear the DS */
4813: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4814: {
4818: DMFieldEnlarge_Static(dm, f+1);
4819: DMLabelDestroy(&dm->fields[f].label);
4820: PetscObjectDestroy(&dm->fields[f].disc);
4821: dm->fields[f].label = label;
4822: dm->fields[f].disc = field;
4823: PetscObjectReference((PetscObject) label);
4824: PetscObjectReference((PetscObject) field);
4825: return(0);
4826: }
4828: /*@
4829: DMSetField - Set the discretization object for a given DM field
4831: Logically collective on dm
4833: Input Parameters:
4834: + dm - The DM
4835: . f - The field number
4836: . label - The label indicating the support of the field, or NULL for the entire mesh
4837: - field - The discretization object
4839: Level: intermediate
4841: .seealso: DMAddField(), DMGetField()
4842: @*/
4843: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4844: {
4851: if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4852: DMSetField_Internal(dm, f, label, field);
4853: DMSetDefaultAdjacency_Private(dm, f, field);
4854: DMClearDS(dm);
4855: return(0);
4856: }
4858: /*@
4859: DMAddField - Add the discretization object for the given DM field
4861: Logically collective on dm
4863: Input Parameters:
4864: + dm - The DM
4865: . label - The label indicating the support of the field, or NULL for the entire mesh
4866: - field - The discretization object
4868: Level: intermediate
4870: .seealso: DMSetField(), DMGetField()
4871: @*/
4872: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4873: {
4874: PetscInt Nf = dm->Nf;
4881: DMFieldEnlarge_Static(dm, Nf+1);
4882: dm->fields[Nf].label = label;
4883: dm->fields[Nf].disc = field;
4884: PetscObjectReference((PetscObject) label);
4885: PetscObjectReference((PetscObject) field);
4886: DMSetDefaultAdjacency_Private(dm, Nf, field);
4887: DMClearDS(dm);
4888: return(0);
4889: }
4891: /*@
4892: DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4894: Logically collective on dm
4896: Input Parameters:
4897: + dm - The DM
4898: . f - The field index
4899: - avoidTensor - The flag to avoid defining the field on tensor cells
4901: Level: intermediate
4903: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4904: @*/
4905: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4906: {
4908: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4909: dm->fields[f].avoidTensor = avoidTensor;
4910: return(0);
4911: }
4913: /*@
4914: DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4916: Logically collective on dm
4918: Input Parameters:
4919: + dm - The DM
4920: - f - The field index
4922: Output Parameter:
4923: . avoidTensor - The flag to avoid defining the field on tensor cells
4925: Level: intermediate
4927: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4928: @*/
4929: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4930: {
4932: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4933: *avoidTensor = dm->fields[f].avoidTensor;
4934: return(0);
4935: }
4937: /*@
4938: DMCopyFields - Copy the discretizations for the DM into another DM
4940: Collective on dm
4942: Input Parameter:
4943: . dm - The DM
4945: Output Parameter:
4946: . newdm - The DM
4948: Level: advanced
4950: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4951: @*/
4952: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4953: {
4954: PetscInt Nf, f;
4958: if (dm == newdm) return(0);
4959: DMGetNumFields(dm, &Nf);
4960: DMClearFields(newdm);
4961: for (f = 0; f < Nf; ++f) {
4962: DMLabel label;
4963: PetscObject field;
4964: PetscBool useCone, useClosure;
4966: DMGetField(dm, f, &label, &field);
4967: DMSetField(newdm, f, label, field);
4968: DMGetAdjacency(dm, f, &useCone, &useClosure);
4969: DMSetAdjacency(newdm, f, useCone, useClosure);
4970: }
4971: return(0);
4972: }
4974: /*@
4975: DMGetAdjacency - Returns the flags for determining variable influence
4977: Not collective
4979: Input Parameters:
4980: + dm - The DM object
4981: - f - The field number, or PETSC_DEFAULT for the default adjacency
4983: Output Parameters:
4984: + useCone - Flag for variable influence starting with the cone operation
4985: - useClosure - Flag for variable influence using transitive closure
4987: Notes:
4988: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4989: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4990: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4991: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4993: Level: developer
4995: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4996: @*/
4997: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4998: {
5003: if (f < 0) {
5004: if (useCone) *useCone = dm->adjacency[0];
5005: if (useClosure) *useClosure = dm->adjacency[1];
5006: } else {
5007: PetscInt Nf;
5010: DMGetNumFields(dm, &Nf);
5011: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5012: if (useCone) *useCone = dm->fields[f].adjacency[0];
5013: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5014: }
5015: return(0);
5016: }
5018: /*@
5019: DMSetAdjacency - Set the flags for determining variable influence
5021: Not collective
5023: Input Parameters:
5024: + dm - The DM object
5025: . f - The field number
5026: . useCone - Flag for variable influence starting with the cone operation
5027: - useClosure - Flag for variable influence using transitive closure
5029: Notes:
5030: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5031: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5032: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5033: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5035: Level: developer
5037: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
5038: @*/
5039: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5040: {
5043: if (f < 0) {
5044: dm->adjacency[0] = useCone;
5045: dm->adjacency[1] = useClosure;
5046: } else {
5047: PetscInt Nf;
5050: DMGetNumFields(dm, &Nf);
5051: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5052: dm->fields[f].adjacency[0] = useCone;
5053: dm->fields[f].adjacency[1] = useClosure;
5054: }
5055: return(0);
5056: }
5058: /*@
5059: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5061: Not collective
5063: Input Parameter:
5064: . dm - The DM object
5066: Output Parameters:
5067: + useCone - Flag for variable influence starting with the cone operation
5068: - useClosure - Flag for variable influence using transitive closure
5070: Notes:
5071: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5072: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5073: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5075: Level: developer
5077: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5078: @*/
5079: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5080: {
5081: PetscInt Nf;
5088: DMGetNumFields(dm, &Nf);
5089: if (!Nf) {
5090: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5091: } else {
5092: DMGetAdjacency(dm, 0, useCone, useClosure);
5093: }
5094: return(0);
5095: }
5097: /*@
5098: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5100: Not collective
5102: Input Parameters:
5103: + dm - The DM object
5104: . useCone - Flag for variable influence starting with the cone operation
5105: - useClosure - Flag for variable influence using transitive closure
5107: Notes:
5108: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5109: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5110: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5112: Level: developer
5114: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5115: @*/
5116: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5117: {
5118: PetscInt Nf;
5123: DMGetNumFields(dm, &Nf);
5124: if (!Nf) {
5125: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5126: } else {
5127: DMSetAdjacency(dm, 0, useCone, useClosure);
5128: }
5129: return(0);
5130: }
5132: /* Complete labels that are being used for FEM BC */
5133: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
5134: {
5135: PetscObject obj;
5136: PetscClassId id;
5137: PetscInt Nbd, bd;
5138: PetscBool isFE = PETSC_FALSE;
5139: PetscBool duplicate = PETSC_FALSE;
5143: DMGetField(dm, field, NULL, &obj);
5144: PetscObjectGetClassId(obj, &id);
5145: if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5146: if (isFE && label) {
5147: /* Only want to modify label once */
5148: PetscDSGetNumBoundary(ds, &Nbd);
5149: for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5150: DMLabel l;
5152: PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5153: duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
5154: if (duplicate) break;
5155: }
5156: if (!duplicate) {
5157: DM plex;
5159: DMConvert(dm, DMPLEX, &plex);
5160: if (plex) {DMPlexLabelComplete(plex, label);}
5161: DMDestroy(&plex);
5162: }
5163: }
5164: return(0);
5165: }
5167: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5168: {
5169: DMSpace *tmpd;
5170: PetscInt Nds = dm->Nds, s;
5174: if (Nds >= NdsNew) return(0);
5175: PetscMalloc1(NdsNew, &tmpd);
5176: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5177: for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5178: PetscFree(dm->probs);
5179: dm->Nds = NdsNew;
5180: dm->probs = tmpd;
5181: return(0);
5182: }
5184: /*@
5185: DMGetNumDS - Get the number of discrete systems in the DM
5187: Not collective
5189: Input Parameter:
5190: . dm - The DM
5192: Output Parameter:
5193: . Nds - The number of PetscDS objects
5195: Level: intermediate
5197: .seealso: DMGetDS(), DMGetCellDS()
5198: @*/
5199: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5200: {
5204: *Nds = dm->Nds;
5205: return(0);
5206: }
5208: /*@
5209: DMClearDS - Remove all discrete systems from the DM
5211: Logically collective on dm
5213: Input Parameter:
5214: . dm - The DM
5216: Level: intermediate
5218: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5219: @*/
5220: PetscErrorCode DMClearDS(DM dm)
5221: {
5222: PetscInt s;
5227: for (s = 0; s < dm->Nds; ++s) {
5228: PetscDSDestroy(&dm->probs[s].ds);
5229: DMLabelDestroy(&dm->probs[s].label);
5230: ISDestroy(&dm->probs[s].fields);
5231: }
5232: PetscFree(dm->probs);
5233: dm->probs = NULL;
5234: dm->Nds = 0;
5235: return(0);
5236: }
5238: /*@
5239: DMGetDS - Get the default PetscDS
5241: Not collective
5243: Input Parameter:
5244: . dm - The DM
5246: Output Parameter:
5247: . prob - The default PetscDS
5249: Level: intermediate
5251: .seealso: DMGetCellDS(), DMGetRegionDS()
5252: @*/
5253: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5254: {
5260: if (dm->Nds <= 0) {
5261: PetscDS ds;
5263: PetscDSCreate(PETSC_COMM_SELF, &ds);
5264: DMSetRegionDS(dm, NULL, NULL, ds);
5265: PetscDSDestroy(&ds);
5266: }
5267: *prob = dm->probs[0].ds;
5268: return(0);
5269: }
5271: /*@
5272: DMGetCellDS - Get the PetscDS defined on a given cell
5274: Not collective
5276: Input Parameters:
5277: + dm - The DM
5278: - point - Cell for the DS
5280: Output Parameter:
5281: . prob - The PetscDS defined on the given cell
5283: Level: developer
5285: .seealso: DMGetDS(), DMSetRegionDS()
5286: @*/
5287: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5288: {
5289: PetscDS probDef = NULL;
5290: PetscInt s;
5296: if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5297: *prob = NULL;
5298: for (s = 0; s < dm->Nds; ++s) {
5299: PetscInt val;
5301: if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5302: else {
5303: DMLabelGetValue(dm->probs[s].label, point, &val);
5304: if (val >= 0) {*prob = dm->probs[s].ds; break;}
5305: }
5306: }
5307: if (!*prob) *prob = probDef;
5308: return(0);
5309: }
5311: /*@
5312: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5314: Not collective
5316: Input Parameters:
5317: + dm - The DM
5318: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5320: Output Parameters:
5321: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5322: - prob - The PetscDS defined on the given region, or NULL
5324: Note: If the label is missing, this function returns an error
5326: Level: advanced
5328: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5329: @*/
5330: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5331: {
5332: PetscInt Nds = dm->Nds, s;
5339: for (s = 0; s < Nds; ++s) {
5340: if (dm->probs[s].label == label) {
5341: if (fields) *fields = dm->probs[s].fields;
5342: if (ds) *ds = dm->probs[s].ds;
5343: return(0);
5344: }
5345: }
5346: return(0);
5347: }
5349: /*@
5350: DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5352: Collective on dm
5354: Input Parameters:
5355: + dm - The DM
5356: . label - The DMLabel defining the mesh region, or NULL for the entire mesh
5357: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5358: - prob - The PetscDS defined on the given cell
5360: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5361: the fields argument is ignored.
5363: Level: advanced
5365: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5366: @*/
5367: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5368: {
5369: PetscInt Nds = dm->Nds, s;
5376: for (s = 0; s < Nds; ++s) {
5377: if (dm->probs[s].label == label) {
5378: PetscDSDestroy(&dm->probs[s].ds);
5379: dm->probs[s].ds = ds;
5380: return(0);
5381: }
5382: }
5383: DMDSEnlarge_Static(dm, Nds+1);
5384: PetscObjectReference((PetscObject) label);
5385: PetscObjectReference((PetscObject) fields);
5386: PetscObjectReference((PetscObject) ds);
5387: if (!label) {
5388: /* Put the NULL label at the front, so it is returned as the default */
5389: for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5390: Nds = 0;
5391: }
5392: dm->probs[Nds].label = label;
5393: dm->probs[Nds].fields = fields;
5394: dm->probs[Nds].ds = ds;
5395: return(0);
5396: }
5398: /*@
5399: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5401: Not collective
5403: Input Parameters:
5404: + dm - The DM
5405: - num - The region number, in [0, Nds)
5407: Output Parameters:
5408: + label - The region label, or NULL
5409: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5410: - ds - The PetscDS defined on the given region, or NULL
5412: Level: advanced
5414: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5415: @*/
5416: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5417: {
5418: PetscInt Nds;
5423: DMGetNumDS(dm, &Nds);
5424: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5425: if (label) {
5427: *label = dm->probs[num].label;
5428: }
5429: if (fields) {
5431: *fields = dm->probs[num].fields;
5432: }
5433: if (ds) {
5435: *ds = dm->probs[num].ds;
5436: }
5437: return(0);
5438: }
5440: /*@
5441: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5443: Not collective
5445: Input Parameters:
5446: + dm - The DM
5447: . num - The region number, in [0, Nds)
5448: . label - The region label, or NULL
5449: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5450: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5452: Level: advanced
5454: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5455: @*/
5456: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5457: {
5458: PetscInt Nds;
5464: DMGetNumDS(dm, &Nds);
5465: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5466: PetscObjectReference((PetscObject) label);
5467: DMLabelDestroy(&dm->probs[num].label);
5468: dm->probs[num].label = label;
5469: if (fields) {
5471: PetscObjectReference((PetscObject) fields);
5472: ISDestroy(&dm->probs[num].fields);
5473: dm->probs[num].fields = fields;
5474: }
5475: if (ds) {
5477: PetscObjectReference((PetscObject) ds);
5478: PetscDSDestroy(&dm->probs[num].ds);
5479: dm->probs[num].ds = ds;
5480: }
5481: return(0);
5482: }
5484: /*@
5485: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5487: Not collective
5489: Input Parameters:
5490: + dm - The DM
5491: - ds - The PetscDS defined on the given region
5493: Output Parameter:
5494: . num - The region number, in [0, Nds), or -1 if not found
5496: Level: advanced
5498: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5499: @*/
5500: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5501: {
5502: PetscInt Nds, n;
5509: DMGetNumDS(dm, &Nds);
5510: for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5511: if (n >= Nds) *num = -1;
5512: else *num = n;
5513: return(0);
5514: }
5516: /*@
5517: DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5519: Collective on dm
5521: Input Parameter:
5522: . dm - The DM
5524: Options Database Keys:
5525: . -dm_petscds_view - View all the PetscDS objects in this DM
5527: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5529: Level: intermediate
5531: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5532: @*/
5533: PetscErrorCode DMCreateDS(DM dm)
5534: {
5535: MPI_Comm comm;
5536: PetscDS dsDef;
5537: DMLabel *labelSet;
5538: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5539: PetscBool doSetup = PETSC_TRUE, flg;
5544: if (!dm->fields) return(0);
5545: PetscObjectGetComm((PetscObject) dm, &comm);
5546: DMGetCoordinateDim(dm, &dE);
5547: /* Determine how many regions we have */
5548: PetscMalloc1(Nf, &labelSet);
5549: Nl = 0;
5550: Ndef = 0;
5551: for (f = 0; f < Nf; ++f) {
5552: DMLabel label = dm->fields[f].label;
5553: PetscInt l;
5555: #ifdef PETSC_HAVE_LIBCEED
5556: /* Move CEED context to discretizations */
5557: {
5558: PetscClassId id;
5560: PetscObjectGetClassId(dm->fields[f].disc, &id);
5561: if (id == PETSCFE_CLASSID) {
5562: Ceed ceed;
5564: DMGetCeed(dm, &ceed);
5565: PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
5566: }
5567: }
5568: #endif
5569: if (!label) {++Ndef; continue;}
5570: for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5571: if (l < Nl) continue;
5572: labelSet[Nl++] = label;
5573: }
5574: /* Create default DS if there are no labels to intersect with */
5575: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5576: if (!dsDef && Ndef && !Nl) {
5577: IS fields;
5578: PetscInt *fld, nf;
5580: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5581: if (nf) {
5582: PetscMalloc1(nf, &fld);
5583: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5584: ISCreate(PETSC_COMM_SELF, &fields);
5585: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5586: ISSetType(fields, ISGENERAL);
5587: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5589: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5590: DMSetRegionDS(dm, NULL, fields, dsDef);
5591: PetscDSDestroy(&dsDef);
5592: ISDestroy(&fields);
5593: }
5594: }
5595: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5596: if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5597: /* Intersect labels with default fields */
5598: if (Ndef && Nl) {
5599: DM plex;
5600: DMLabel cellLabel;
5601: IS fieldIS, allcellIS, defcellIS = NULL;
5602: PetscInt *fields;
5603: const PetscInt *cells;
5604: PetscInt depth, nf = 0, n, c;
5606: DMConvert(dm, DMPLEX, &plex);
5607: DMPlexGetDepth(plex, &depth);
5608: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5609: if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5610: for (l = 0; l < Nl; ++l) {
5611: DMLabel label = labelSet[l];
5612: IS pointIS;
5614: ISDestroy(&defcellIS);
5615: DMLabelGetStratumIS(label, 1, &pointIS);
5616: ISDifference(allcellIS, pointIS, &defcellIS);
5617: ISDestroy(&pointIS);
5618: }
5619: ISDestroy(&allcellIS);
5621: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5622: ISGetLocalSize(defcellIS, &n);
5623: ISGetIndices(defcellIS, &cells);
5624: for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5625: ISRestoreIndices(defcellIS, &cells);
5626: ISDestroy(&defcellIS);
5627: DMPlexLabelComplete(plex, cellLabel);
5629: PetscMalloc1(Ndef, &fields);
5630: for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5631: ISCreate(PETSC_COMM_SELF, &fieldIS);
5632: PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5633: ISSetType(fieldIS, ISGENERAL);
5634: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5636: PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5637: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5638: DMLabelDestroy(&cellLabel);
5639: PetscDSSetCoordinateDimension(dsDef, dE);
5640: PetscDSDestroy(&dsDef);
5641: ISDestroy(&fieldIS);
5642: DMDestroy(&plex);
5643: }
5644: /* Create label DSes
5645: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5646: */
5647: /* TODO Should check that labels are disjoint */
5648: for (l = 0; l < Nl; ++l) {
5649: DMLabel label = labelSet[l];
5650: PetscDS ds;
5651: IS fields;
5652: PetscInt *fld, nf;
5654: PetscDSCreate(PETSC_COMM_SELF, &ds);
5655: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5656: PetscMalloc1(nf, &fld);
5657: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5658: ISCreate(PETSC_COMM_SELF, &fields);
5659: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5660: ISSetType(fields, ISGENERAL);
5661: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5662: DMSetRegionDS(dm, label, fields, ds);
5663: ISDestroy(&fields);
5664: PetscDSSetCoordinateDimension(ds, dE);
5665: {
5666: DMPolytopeType ct;
5667: PetscInt lStart, lEnd;
5668: PetscBool isHybridLocal = PETSC_FALSE, isHybrid;
5670: DMLabelGetBounds(label, &lStart, &lEnd);
5671: if (lStart >= 0) {
5672: DMPlexGetCellType(dm, lStart, &ct);
5673: switch (ct) {
5674: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5675: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5676: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5677: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5678: isHybridLocal = PETSC_TRUE;break;
5679: default: break;
5680: }
5681: }
5682: MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5683: PetscDSSetHybrid(ds, isHybrid);
5684: }
5685: PetscDSDestroy(&ds);
5686: }
5687: PetscFree(labelSet);
5688: /* Set fields in DSes */
5689: for (s = 0; s < dm->Nds; ++s) {
5690: PetscDS ds = dm->probs[s].ds;
5691: IS fields = dm->probs[s].fields;
5692: const PetscInt *fld;
5693: PetscInt nf;
5695: ISGetLocalSize(fields, &nf);
5696: ISGetIndices(fields, &fld);
5697: for (f = 0; f < nf; ++f) {
5698: PetscObject disc = dm->fields[fld[f]].disc;
5699: PetscBool isHybrid;
5700: PetscClassId id;
5702: PetscDSGetHybrid(ds, &isHybrid);
5703: /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5704: if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5705: PetscDSSetDiscretization(ds, f, disc);
5706: /* We allow people to have placeholder fields and construct the Section by hand */
5707: PetscObjectGetClassId(disc, &id);
5708: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5709: }
5710: ISRestoreIndices(fields, &fld);
5711: }
5712: /* Allow k-jet tabulation */
5713: PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5714: if (flg) {
5715: for (s = 0; s < dm->Nds; ++s) {
5716: PetscDS ds = dm->probs[s].ds;
5717: PetscInt Nf, f;
5719: PetscDSGetNumFields(ds, &Nf);
5720: for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5721: }
5722: }
5723: /* Setup DSes */
5724: if (doSetup) {
5725: for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5726: }
5727: return(0);
5728: }
5730: /*@
5731: DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5733: Collective on DM
5735: Input Parameters:
5736: + dm - The DM
5737: - time - The time
5739: Output Parameters:
5740: + u - The vector will be filled with exact solution values, or NULL
5741: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5743: Note: The user must call PetscDSSetExactSolution() beforehand
5745: Level: developer
5747: .seealso: PetscDSSetExactSolution()
5748: @*/
5749: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5750: {
5751: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5752: void **ectxs;
5753: PetscInt Nf, Nds, s;
5754: PetscErrorCode ierr;
5760: DMGetNumFields(dm, &Nf);
5761: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5762: DMGetNumDS(dm, &Nds);
5763: for (s = 0; s < Nds; ++s) {
5764: PetscDS ds;
5765: DMLabel label;
5766: IS fieldIS;
5767: const PetscInt *fields, id = 1;
5768: PetscInt dsNf, f;
5770: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5771: PetscDSGetNumFields(ds, &dsNf);
5772: ISGetIndices(fieldIS, &fields);
5773: PetscArrayzero(exacts, Nf);
5774: PetscArrayzero(ectxs, Nf);
5775: if (u) {
5776: for (f = 0; f < dsNf; ++f) {
5777: const PetscInt field = fields[f];
5778: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5779: }
5780: ISRestoreIndices(fieldIS, &fields);
5781: if (label) {
5782: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5783: } else {
5784: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5785: }
5786: }
5787: if (u_t) {
5788: PetscArrayzero(exacts, Nf);
5789: PetscArrayzero(ectxs, Nf);
5790: for (f = 0; f < dsNf; ++f) {
5791: const PetscInt field = fields[f];
5792: PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5793: }
5794: ISRestoreIndices(fieldIS, &fields);
5795: if (label) {
5796: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5797: } else {
5798: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5799: }
5800: }
5801: }
5802: if (u) {
5803: PetscObjectSetName((PetscObject) u, "Exact Solution");
5804: PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5805: }
5806: if (u_t) {
5807: PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5808: PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5809: }
5810: PetscFree2(exacts, ectxs);
5811: return(0);
5812: }
5814: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5815: {
5816: PetscDS dsNew;
5817: DSBoundary b;
5818: PetscInt cdim, Nf, f;
5819: PetscBool isHybrid;
5820: void *ctx;
5824: PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5825: PetscDSCopyConstants(ds, dsNew);
5826: PetscDSCopyExactSolutions(ds, dsNew);
5827: PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5828: PetscDSCopyEquations(ds, dsNew);
5829: PetscDSGetNumFields(ds, &Nf);
5830: for (f = 0; f < Nf; ++f) {
5831: PetscDSGetContext(ds, f, &ctx);
5832: PetscDSSetContext(dsNew, f, ctx);
5833: }
5834: if (Nf) {
5835: PetscDSGetCoordinateDimension(ds, &cdim);
5836: PetscDSSetCoordinateDimension(dsNew, cdim);
5837: }
5838: PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5839: for (b = dsNew->boundary; b; b = b->next) {
5840: DMGetLabel(dm, b->lname, &b->label);
5841: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5842: //if (!b->label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
5843: }
5844: PetscDSGetHybrid(ds, &isHybrid);
5845: PetscDSSetHybrid(dsNew, isHybrid);
5847: DMSetRegionDS(dm, label, fields, dsNew);
5848: PetscDSDestroy(&dsNew);
5849: return(0);
5850: }
5852: /*@
5853: DMCopyDS - Copy the discrete systems for the DM into another DM
5855: Collective on dm
5857: Input Parameter:
5858: . dm - The DM
5860: Output Parameter:
5861: . newdm - The DM
5863: Level: advanced
5865: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5866: @*/
5867: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5868: {
5869: PetscInt Nds, s;
5873: if (dm == newdm) return(0);
5874: DMGetNumDS(dm, &Nds);
5875: DMClearDS(newdm);
5876: for (s = 0; s < Nds; ++s) {
5877: DMLabel label;
5878: IS fields;
5879: PetscDS ds, newds;
5880: PetscInt Nbd, bd;
5882: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5883: /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5884: DMTransferDS_Internal(newdm, label, fields, ds);
5885: /* Commplete new labels in the new DS */
5886: DMGetRegionDS(newdm, label, NULL, &newds);
5887: PetscDSGetNumBoundary(newds, &Nbd);
5888: for (bd = 0; bd < Nbd; ++bd) {
5889: PetscWeakForm wf;
5890: DMLabel label;
5891: PetscInt field;
5893: PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5894: DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5895: PetscWeakFormReplaceLabel(wf, label);
5896: }
5897: }
5898: return(0);
5899: }
5901: /*@
5902: DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5904: Collective on dm
5906: Input Parameter:
5907: . dm - The DM
5909: Output Parameter:
5910: . newdm - The DM
5912: Level: advanced
5914: .seealso: DMCopyFields(), DMCopyDS()
5915: @*/
5916: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5917: {
5921: DMCopyFields(dm, newdm);
5922: DMCopyDS(dm, newdm);
5923: return(0);
5924: }
5926: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5927: {
5928: DM dm_coord,dmc_coord;
5930: Vec coords,ccoords;
5931: Mat inject;
5933: DMGetCoordinateDM(dm,&dm_coord);
5934: DMGetCoordinateDM(dmc,&dmc_coord);
5935: DMGetCoordinates(dm,&coords);
5936: DMGetCoordinates(dmc,&ccoords);
5937: if (coords && !ccoords) {
5938: DMCreateGlobalVector(dmc_coord,&ccoords);
5939: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5940: DMCreateInjection(dmc_coord,dm_coord,&inject);
5941: MatRestrict(inject,coords,ccoords);
5942: MatDestroy(&inject);
5943: DMSetCoordinates(dmc,ccoords);
5944: VecDestroy(&ccoords);
5945: }
5946: return(0);
5947: }
5949: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5950: {
5951: DM dm_coord,subdm_coord;
5953: Vec coords,ccoords,clcoords;
5954: VecScatter *scat_i,*scat_g;
5956: DMGetCoordinateDM(dm,&dm_coord);
5957: DMGetCoordinateDM(subdm,&subdm_coord);
5958: DMGetCoordinates(dm,&coords);
5959: DMGetCoordinates(subdm,&ccoords);
5960: if (coords && !ccoords) {
5961: DMCreateGlobalVector(subdm_coord,&ccoords);
5962: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5963: DMCreateLocalVector(subdm_coord,&clcoords);
5964: PetscObjectSetName((PetscObject)clcoords,"coordinates");
5965: DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5966: VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5967: VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5968: VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5969: VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5970: DMSetCoordinates(subdm,ccoords);
5971: DMSetCoordinatesLocal(subdm,clcoords);
5972: VecScatterDestroy(&scat_i[0]);
5973: VecScatterDestroy(&scat_g[0]);
5974: VecDestroy(&ccoords);
5975: VecDestroy(&clcoords);
5976: PetscFree(scat_i);
5977: PetscFree(scat_g);
5978: }
5979: return(0);
5980: }
5982: /*@
5983: DMGetDimension - Return the topological dimension of the DM
5985: Not collective
5987: Input Parameter:
5988: . dm - The DM
5990: Output Parameter:
5991: . dim - The topological dimension
5993: Level: beginner
5995: .seealso: DMSetDimension(), DMCreate()
5996: @*/
5997: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5998: {
6002: *dim = dm->dim;
6003: return(0);
6004: }
6006: /*@
6007: DMSetDimension - Set the topological dimension of the DM
6009: Collective on dm
6011: Input Parameters:
6012: + dm - The DM
6013: - dim - The topological dimension
6015: Level: beginner
6017: .seealso: DMGetDimension(), DMCreate()
6018: @*/
6019: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6020: {
6021: PetscDS ds;
6022: PetscInt Nds, n;
6028: dm->dim = dim;
6029: if (dm->dim >= 0) {
6030: DMGetNumDS(dm, &Nds);
6031: for (n = 0; n < Nds; ++n) {
6032: DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6033: if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
6034: }
6035: }
6036: return(0);
6037: }
6039: /*@
6040: DMGetDimPoints - Get the half-open interval for all points of a given dimension
6042: Collective on dm
6044: Input Parameters:
6045: + dm - the DM
6046: - dim - the dimension
6048: Output Parameters:
6049: + pStart - The first point of the given dimension
6050: - pEnd - The first point following points of the given dimension
6052: Note:
6053: The points are vertices in the Hasse diagram encoding the topology. This is explained in
6054: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6055: then the interval is empty.
6057: Level: intermediate
6059: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
6060: @*/
6061: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6062: {
6063: PetscInt d;
6068: DMGetDimension(dm, &d);
6069: if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
6070: if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
6071: (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
6072: return(0);
6073: }
6075: /*@
6076: DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
6078: Collective on dm
6080: Input Parameters:
6081: + dm - the DM
6082: - c - coordinate vector
6084: Notes:
6085: The coordinates do include those for ghost points, which are in the local vector.
6087: The vector c should be destroyed by the caller.
6089: Level: intermediate
6091: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6092: @*/
6093: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6094: {
6100: PetscObjectReference((PetscObject) c);
6101: VecDestroy(&dm->coordinates);
6102: dm->coordinates = c;
6103: VecDestroy(&dm->coordinatesLocal);
6104: DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6105: DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6106: return(0);
6107: }
6109: /*@
6110: DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
6112: Not collective
6114: Input Parameters:
6115: + dm - the DM
6116: - c - coordinate vector
6118: Notes:
6119: The coordinates of ghost points can be set using DMSetCoordinates()
6120: followed by DMGetCoordinatesLocal(). This is intended to enable the
6121: setting of ghost coordinates outside of the domain.
6123: The vector c should be destroyed by the caller.
6125: Level: intermediate
6127: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6128: @*/
6129: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6130: {
6136: PetscObjectReference((PetscObject) c);
6137: VecDestroy(&dm->coordinatesLocal);
6139: dm->coordinatesLocal = c;
6141: VecDestroy(&dm->coordinates);
6142: return(0);
6143: }
6145: /*@
6146: DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
6148: Collective on dm
6150: Input Parameter:
6151: . dm - the DM
6153: Output Parameter:
6154: . c - global coordinate vector
6156: Note:
6157: This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6158: destroyed the array will no longer be valid.
6160: Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).
6162: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6163: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6165: Level: intermediate
6167: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6168: @*/
6169: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6170: {
6176: if (!dm->coordinates && dm->coordinatesLocal) {
6177: DM cdm = NULL;
6178: PetscBool localized;
6180: DMGetCoordinateDM(dm, &cdm);
6181: DMCreateGlobalVector(cdm, &dm->coordinates);
6182: DMGetCoordinatesLocalized(dm, &localized);
6183: /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6184: if (localized) {
6185: PetscInt cdim;
6187: DMGetCoordinateDim(dm, &cdim);
6188: VecSetBlockSize(dm->coordinates, cdim);
6189: }
6190: PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6191: DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6192: DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6193: }
6194: *c = dm->coordinates;
6195: return(0);
6196: }
6198: /*@
6199: DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6201: Collective on dm
6203: Input Parameter:
6204: . dm - the DM
6206: Level: advanced
6208: .seealso: DMGetCoordinatesLocalNoncollective()
6209: @*/
6210: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6211: {
6216: if (!dm->coordinatesLocal && dm->coordinates) {
6217: DM cdm = NULL;
6218: PetscBool localized;
6220: DMGetCoordinateDM(dm, &cdm);
6221: DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6222: DMGetCoordinatesLocalized(dm, &localized);
6223: /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6224: if (localized) {
6225: PetscInt cdim;
6227: DMGetCoordinateDim(dm, &cdim);
6228: VecSetBlockSize(dm->coordinates, cdim);
6229: }
6230: PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6231: DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6232: DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6233: }
6234: return(0);
6235: }
6237: /*@
6238: DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6240: Collective on dm
6242: Input Parameter:
6243: . dm - the DM
6245: Output Parameter:
6246: . c - coordinate vector
6248: Note:
6249: This is a borrowed reference, so the user should NOT destroy this vector
6251: Each process has the local and ghost coordinates
6253: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6254: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6256: Level: intermediate
6258: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6259: @*/
6260: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6261: {
6267: DMGetCoordinatesLocalSetUp(dm);
6268: *c = dm->coordinatesLocal;
6269: return(0);
6270: }
6272: /*@
6273: DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6275: Not collective
6277: Input Parameter:
6278: . dm - the DM
6280: Output Parameter:
6281: . c - coordinate vector
6283: Level: advanced
6285: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6286: @*/
6287: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6288: {
6292: if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6293: *c = dm->coordinatesLocal;
6294: return(0);
6295: }
6297: /*@
6298: DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6300: Not collective
6302: Input Parameters:
6303: + dm - the DM
6304: - p - the IS of points whose coordinates will be returned
6306: Output Parameters:
6307: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6308: - pCoord - the Vec with coordinates of points in p
6310: Note:
6311: DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6313: This creates a new vector, so the user SHOULD destroy this vector
6315: Each process has the local and ghost coordinates
6317: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6318: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6320: Level: advanced
6322: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6323: @*/
6324: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6325: {
6326: PetscSection cs, newcs;
6327: Vec coords;
6328: const PetscScalar *arr;
6329: PetscScalar *newarr=NULL;
6330: PetscInt n;
6331: PetscErrorCode ierr;
6338: if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6339: if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6340: cs = dm->coordinateDM->localSection;
6341: coords = dm->coordinatesLocal;
6342: VecGetArrayRead(coords, &arr);
6343: PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6344: VecRestoreArrayRead(coords, &arr);
6345: if (pCoord) {
6346: PetscSectionGetStorageSize(newcs, &n);
6347: /* set array in two steps to mimic PETSC_OWN_POINTER */
6348: VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6349: VecReplaceArray(*pCoord, newarr);
6350: } else {
6351: PetscFree(newarr);
6352: }
6353: if (pCoordSection) {*pCoordSection = newcs;}
6354: else {PetscSectionDestroy(&newcs);}
6355: return(0);
6356: }
6358: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6359: {
6365: if (!dm->coordinateField) {
6366: if (dm->ops->createcoordinatefield) {
6367: (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6368: }
6369: }
6370: *field = dm->coordinateField;
6371: return(0);
6372: }
6374: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6375: {
6381: PetscObjectReference((PetscObject)field);
6382: DMFieldDestroy(&dm->coordinateField);
6383: dm->coordinateField = field;
6384: return(0);
6385: }
6387: /*@
6388: DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6390: Collective on dm
6392: Input Parameter:
6393: . dm - the DM
6395: Output Parameter:
6396: . cdm - coordinate DM
6398: Level: intermediate
6400: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6401: @*/
6402: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6403: {
6409: if (!dm->coordinateDM) {
6410: DM cdm;
6412: if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6413: (*dm->ops->createcoordinatedm)(dm, &cdm);
6414: /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6415: * until the call to CreateCoordinateDM) */
6416: DMDestroy(&dm->coordinateDM);
6417: dm->coordinateDM = cdm;
6418: }
6419: *cdm = dm->coordinateDM;
6420: return(0);
6421: }
6423: /*@
6424: DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6426: Logically Collective on dm
6428: Input Parameters:
6429: + dm - the DM
6430: - cdm - coordinate DM
6432: Level: intermediate
6434: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6435: @*/
6436: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6437: {
6443: PetscObjectReference((PetscObject)cdm);
6444: DMDestroy(&dm->coordinateDM);
6445: dm->coordinateDM = cdm;
6446: return(0);
6447: }
6449: /*@
6450: DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6452: Not Collective
6454: Input Parameter:
6455: . dm - The DM object
6457: Output Parameter:
6458: . dim - The embedding dimension
6460: Level: intermediate
6462: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6463: @*/
6464: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6465: {
6469: if (dm->dimEmbed == PETSC_DEFAULT) {
6470: dm->dimEmbed = dm->dim;
6471: }
6472: *dim = dm->dimEmbed;
6473: return(0);
6474: }
6476: /*@
6477: DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6479: Not Collective
6481: Input Parameters:
6482: + dm - The DM object
6483: - dim - The embedding dimension
6485: Level: intermediate
6487: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6488: @*/
6489: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6490: {
6491: PetscDS ds;
6492: PetscInt Nds, n;
6497: dm->dimEmbed = dim;
6498: if (dm->dim >= 0) {
6499: DMGetNumDS(dm, &Nds);
6500: for (n = 0; n < Nds; ++n) {
6501: DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6502: PetscDSSetCoordinateDimension(ds, dim);
6503: }
6504: }
6505: return(0);
6506: }
6508: /*@
6509: DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6511: Collective on dm
6513: Input Parameter:
6514: . dm - The DM object
6516: Output Parameter:
6517: . section - The PetscSection object
6519: Level: intermediate
6521: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6522: @*/
6523: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6524: {
6525: DM cdm;
6531: DMGetCoordinateDM(dm, &cdm);
6532: DMGetLocalSection(cdm, section);
6533: return(0);
6534: }
6536: /*@
6537: DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6539: Not Collective
6541: Input Parameters:
6542: + dm - The DM object
6543: . dim - The embedding dimension, or PETSC_DETERMINE
6544: - section - The PetscSection object
6546: Level: intermediate
6548: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6549: @*/
6550: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6551: {
6552: DM cdm;
6558: DMGetCoordinateDM(dm, &cdm);
6559: DMSetLocalSection(cdm, section);
6560: if (dim == PETSC_DETERMINE) {
6561: PetscInt d = PETSC_DEFAULT;
6562: PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6564: PetscSectionGetChart(section, &pStart, &pEnd);
6565: DMGetDimPoints(dm, 0, &vStart, &vEnd);
6566: pStart = PetscMax(vStart, pStart);
6567: pEnd = PetscMin(vEnd, pEnd);
6568: for (v = pStart; v < pEnd; ++v) {
6569: PetscSectionGetDof(section, v, &dd);
6570: if (dd) {d = dd; break;}
6571: }
6572: if (d >= 0) {DMSetCoordinateDim(dm, d);}
6573: }
6574: return(0);
6575: }
6577: /*@
6578: DMProjectCoordinates - Project coordinates to a different space
6580: Input Parameters:
6581: + dm - The DM object
6582: - disc - The new coordinate discretization
6584: Level: intermediate
6586: .seealso: DMGetCoordinateField()
6587: @*/
6588: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6589: {
6590: PetscObject discOld;
6591: PetscClassId classid;
6592: DM cdmOld,cdmNew;
6593: Vec coordsOld,coordsNew;
6594: Mat matInterp;
6601: DMGetCoordinateDM(dm, &cdmOld);
6602: /* Check current discretization is compatible */
6603: DMGetField(cdmOld, 0, NULL, &discOld);
6604: PetscObjectGetClassId(discOld, &classid);
6605: if (classid != PETSCFE_CLASSID) {
6606: if (classid == PETSC_CONTAINER_CLASSID) {
6607: PetscFE feLinear;
6608: DMPolytopeType ct;
6609: PetscInt dim, dE, cStart;
6610: PetscBool simplex;
6612: /* Assume linear vertex coordinates */
6613: DMGetDimension(dm, &dim);
6614: DMGetCoordinateDim(dm, &dE);
6615: DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6616: DMPlexGetCellType(dm, cStart, &ct);
6617: switch (ct) {
6618: case DM_POLYTOPE_TRI_PRISM:
6619: case DM_POLYTOPE_TRI_PRISM_TENSOR:
6620: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6621: default: break;
6622: }
6623: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6624: PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6625: DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6626: PetscFEDestroy(&feLinear);
6627: DMCreateDS(cdmOld);
6628: } else {
6629: const char *discname;
6631: PetscObjectGetType(discOld, &discname);
6632: SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6633: }
6634: }
6635: /* Make a fresh clone of the coordinate DM */
6636: DMClone(cdmOld, &cdmNew);
6637: DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6638: DMCreateDS(cdmNew);
6639: /* Project the coordinate vector from old to new space */
6640: DMGetCoordinates(dm, &coordsOld);
6641: DMCreateGlobalVector(cdmNew, &coordsNew);
6642: DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6643: MatInterpolate(matInterp, coordsOld, coordsNew);
6644: MatDestroy(&matInterp);
6645: /* Set new coordinate structures */
6646: DMSetCoordinateField(dm, NULL);
6647: DMSetCoordinateDM(dm, cdmNew);
6648: DMSetCoordinates(dm, coordsNew);
6649: VecDestroy(&coordsNew);
6650: DMDestroy(&cdmNew);
6651: return(0);
6652: }
6654: /*@C
6655: DMGetPeriodicity - Get the description of mesh periodicity
6657: Input Parameter:
6658: . dm - The DM object
6660: Output Parameters:
6661: + per - Whether the DM is periodic or not
6662: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6663: . L - If we assume the mesh is a torus, this is the length of each coordinate
6664: - bd - This describes the type of periodicity in each topological dimension
6666: Level: developer
6668: .seealso: DMGetPeriodicity()
6669: @*/
6670: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6671: {
6674: if (per) *per = dm->periodic;
6675: if (L) *L = dm->L;
6676: if (maxCell) *maxCell = dm->maxCell;
6677: if (bd) *bd = dm->bdtype;
6678: return(0);
6679: }
6681: /*@C
6682: DMSetPeriodicity - Set the description of mesh periodicity
6684: Input Parameters:
6685: + dm - The DM object
6686: . per - Whether the DM is periodic or not.
6687: . 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.
6688: . L - If we assume the mesh is a torus, this is the length of each coordinate
6689: - bd - This describes the type of periodicity in each topological dimension
6691: 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.
6693: Level: developer
6695: .seealso: DMGetPeriodicity()
6696: @*/
6697: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6698: {
6699: PetscInt dim, d;
6708: DMGetDimension(dm, &dim);
6709: if (maxCell) {
6710: if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6711: for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6712: } else { /* remove maxCell information to disable automatic computation of localized vertices */
6713: PetscFree(dm->maxCell);
6714: }
6716: if (L) {
6717: if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6718: for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6719: }
6720: if (bd) {
6721: if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6722: for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6723: }
6724: dm->periodic = per;
6725: return(0);
6726: }
6728: /*@
6729: 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.
6731: Input Parameters:
6732: + dm - The DM
6733: . in - The input coordinate point (dim numbers)
6734: - endpoint - Include the endpoint L_i
6736: Output Parameter:
6737: . out - The localized coordinate point
6739: Level: developer
6741: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6742: @*/
6743: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6744: {
6745: PetscInt dim, d;
6749: DMGetCoordinateDim(dm, &dim);
6750: if (!dm->maxCell) {
6751: for (d = 0; d < dim; ++d) out[d] = in[d];
6752: } else {
6753: if (endpoint) {
6754: for (d = 0; d < dim; ++d) {
6755: 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)) {
6756: out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6757: } else {
6758: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6759: }
6760: }
6761: } else {
6762: for (d = 0; d < dim; ++d) {
6763: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6764: }
6765: }
6766: }
6767: return(0);
6768: }
6770: /*
6771: 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.
6773: Input Parameters:
6774: + dm - The DM
6775: . dim - The spatial dimension
6776: . anchor - The anchor point, the input point can be no more than maxCell away from it
6777: - in - The input coordinate point (dim numbers)
6779: Output Parameter:
6780: . out - The localized coordinate point
6782: Level: developer
6784: 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
6786: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6787: */
6788: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6789: {
6790: PetscInt d;
6793: if (!dm->maxCell) {
6794: for (d = 0; d < dim; ++d) out[d] = in[d];
6795: } else {
6796: for (d = 0; d < dim; ++d) {
6797: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6798: out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6799: } else {
6800: out[d] = in[d];
6801: }
6802: }
6803: }
6804: return(0);
6805: }
6807: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6808: {
6809: PetscInt d;
6812: if (!dm->maxCell) {
6813: for (d = 0; d < dim; ++d) out[d] = in[d];
6814: } else {
6815: for (d = 0; d < dim; ++d) {
6816: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6817: out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6818: } else {
6819: out[d] = in[d];
6820: }
6821: }
6822: }
6823: return(0);
6824: }
6826: /*
6827: 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.
6829: Input Parameters:
6830: + dm - The DM
6831: . dim - The spatial dimension
6832: . anchor - The anchor point, the input point can be no more than maxCell away from it
6833: . in - The input coordinate delta (dim numbers)
6834: - out - The input coordinate point (dim numbers)
6836: Output Parameter:
6837: . out - The localized coordinate in + out
6839: Level: developer
6841: 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
6843: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6844: */
6845: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6846: {
6847: PetscInt d;
6850: if (!dm->maxCell) {
6851: for (d = 0; d < dim; ++d) out[d] += in[d];
6852: } else {
6853: for (d = 0; d < dim; ++d) {
6854: const PetscReal maxC = dm->maxCell[d];
6856: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6857: const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6859: if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6860: SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
6861: out[d] += newCoord;
6862: } else {
6863: out[d] += in[d];
6864: }
6865: }
6866: }
6867: return(0);
6868: }
6870: /*@
6871: DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6873: Not collective
6875: Input Parameter:
6876: . dm - The DM
6878: Output Parameter:
6879: areLocalized - True if localized
6881: Level: developer
6883: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6884: @*/
6885: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6886: {
6887: DM cdm;
6888: PetscSection coordSection;
6889: PetscInt depth, cStart, cEnd, sStart, sEnd, c, dof;
6890: PetscBool isPlex, alreadyLocalized;
6896: *areLocalized = PETSC_FALSE;
6898: /* We need some generic way of refering to cells/vertices */
6899: DMGetCoordinateDM(dm, &cdm);
6900: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6901: if (!isPlex) return(0);
6902: DMPlexGetDepth(cdm, &depth);
6903: if (!depth) return(0);
6905: DMGetCoordinateSection(dm, &coordSection);
6906: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6907: PetscSectionGetChart(coordSection, &sStart, &sEnd);
6908: alreadyLocalized = PETSC_FALSE;
6909: for (c = cStart; c < cEnd; ++c) {
6910: if (c < sStart || c >= sEnd) continue;
6911: PetscSectionGetDof(coordSection, c, &dof);
6912: if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6913: }
6914: *areLocalized = alreadyLocalized;
6915: return(0);
6916: }
6918: /*@
6919: DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6921: Collective on dm
6923: Input Parameter:
6924: . dm - The DM
6926: Output Parameter:
6927: areLocalized - True if localized
6929: Level: developer
6931: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6932: @*/
6933: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6934: {
6935: PetscBool localized;
6941: DMGetCoordinatesLocalizedLocal(dm,&localized);
6942: MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6943: return(0);
6944: }
6946: /*@
6947: DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6949: Collective on dm
6951: Input Parameter:
6952: . dm - The DM
6954: Level: developer
6956: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6957: @*/
6958: PetscErrorCode DMLocalizeCoordinates(DM dm)
6959: {
6960: DM cdm;
6961: PetscSection coordSection, cSection;
6962: Vec coordinates, cVec;
6963: PetscScalar *coords, *coords2, *anchor, *localized;
6964: PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6965: PetscBool alreadyLocalized, alreadyLocalizedGlobal;
6966: PetscInt maxHeight = 0, h;
6967: PetscInt *pStart = NULL, *pEnd = NULL;
6972: if (!dm->periodic) return(0);
6973: DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6974: if (alreadyLocalized) return(0);
6976: /* We need some generic way of refering to cells/vertices */
6977: DMGetCoordinateDM(dm, &cdm);
6978: {
6979: PetscBool isplex;
6981: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6982: if (isplex) {
6983: DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6984: DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6985: DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6986: pEnd = &pStart[maxHeight + 1];
6987: newStart = vStart;
6988: newEnd = vEnd;
6989: for (h = 0; h <= maxHeight; h++) {
6990: DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6991: newStart = PetscMin(newStart,pStart[h]);
6992: newEnd = PetscMax(newEnd,pEnd[h]);
6993: }
6994: } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6995: }
6996: DMGetCoordinatesLocal(dm, &coordinates);
6997: if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6998: DMGetCoordinateSection(dm, &coordSection);
6999: VecGetBlockSize(coordinates, &bs);
7000: PetscSectionGetChart(coordSection,&sStart,&sEnd);
7002: PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
7003: PetscSectionSetNumFields(cSection, 1);
7004: PetscSectionGetFieldComponents(coordSection, 0, &Nc);
7005: PetscSectionSetFieldComponents(cSection, 0, Nc);
7006: PetscSectionSetChart(cSection, newStart, newEnd);
7008: DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7009: localized = &anchor[bs];
7010: alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7011: for (h = 0; h <= maxHeight; h++) {
7012: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7014: for (c = cStart; c < cEnd; ++c) {
7015: PetscScalar *cellCoords = NULL;
7016: PetscInt b;
7018: if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7019: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7020: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7021: for (d = 0; d < dof/bs; ++d) {
7022: DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
7023: for (b = 0; b < bs; b++) {
7024: if (cellCoords[d*bs + b] != localized[b]) break;
7025: }
7026: if (b < bs) break;
7027: }
7028: if (d < dof/bs) {
7029: if (c >= sStart && c < sEnd) {
7030: PetscInt cdof;
7032: PetscSectionGetDof(coordSection, c, &cdof);
7033: if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7034: }
7035: PetscSectionSetDof(cSection, c, dof);
7036: PetscSectionSetFieldDof(cSection, c, 0, dof);
7037: }
7038: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7039: }
7040: }
7041: MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
7042: if (alreadyLocalizedGlobal) {
7043: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7044: PetscSectionDestroy(&cSection);
7045: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7046: return(0);
7047: }
7048: for (v = vStart; v < vEnd; ++v) {
7049: PetscSectionGetDof(coordSection, v, &dof);
7050: PetscSectionSetDof(cSection, v, dof);
7051: PetscSectionSetFieldDof(cSection, v, 0, dof);
7052: }
7053: PetscSectionSetUp(cSection);
7054: PetscSectionGetStorageSize(cSection, &coordSize);
7055: VecCreate(PETSC_COMM_SELF, &cVec);
7056: PetscObjectSetName((PetscObject)cVec,"coordinates");
7057: VecSetBlockSize(cVec, bs);
7058: VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
7059: VecSetType(cVec, VECSTANDARD);
7060: VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
7061: VecGetArray(cVec, &coords2);
7062: for (v = vStart; v < vEnd; ++v) {
7063: PetscSectionGetDof(coordSection, v, &dof);
7064: PetscSectionGetOffset(coordSection, v, &off);
7065: PetscSectionGetOffset(cSection, v, &off2);
7066: for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7067: }
7068: for (h = 0; h <= maxHeight; h++) {
7069: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7071: for (c = cStart; c < cEnd; ++c) {
7072: PetscScalar *cellCoords = NULL;
7073: PetscInt b, cdof;
7075: PetscSectionGetDof(cSection,c,&cdof);
7076: if (!cdof) continue;
7077: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7078: PetscSectionGetOffset(cSection, c, &off2);
7079: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7080: for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
7081: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7082: }
7083: }
7084: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7085: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7086: VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
7087: VecRestoreArray(cVec, &coords2);
7088: DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
7089: DMSetCoordinatesLocal(dm, cVec);
7090: VecDestroy(&cVec);
7091: PetscSectionDestroy(&cSection);
7092: return(0);
7093: }
7095: /*@
7096: DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
7098: Collective on v (see explanation below)
7100: Input Parameters:
7101: + dm - The DM
7102: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
7104: Input/Output Parameters:
7105: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7106: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7107: on output, the PetscSF containing the ranks and local indices of the containing points
7109: Level: developer
7111: Notes:
7112: To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7113: To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
7115: If *cellSF is NULL on input, a PetscSF will be created.
7116: If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
7118: An array that maps each point to its containing cell can be obtained with
7120: $ const PetscSFNode *cells;
7121: $ PetscInt nFound;
7122: $ const PetscInt *found;
7123: $
7124: $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
7126: Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7127: the index of the cell in its rank's local numbering.
7129: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7130: @*/
7131: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7132: {
7139: if (*cellSF) {
7140: PetscMPIInt result;
7143: MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7144: if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7145: } else {
7146: PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7147: }
7148: if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7149: PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7150: (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7151: PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7152: return(0);
7153: }
7155: /*@
7156: DMGetOutputDM - Retrieve the DM associated with the layout for output
7158: Collective on dm
7160: Input Parameter:
7161: . dm - The original DM
7163: Output Parameter:
7164: . odm - The DM which provides the layout for output
7166: Level: intermediate
7168: .seealso: VecView(), DMGetGlobalSection()
7169: @*/
7170: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7171: {
7172: PetscSection section;
7173: PetscBool hasConstraints, ghasConstraints;
7179: DMGetLocalSection(dm, §ion);
7180: PetscSectionHasConstraints(section, &hasConstraints);
7181: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7182: if (!ghasConstraints) {
7183: *odm = dm;
7184: return(0);
7185: }
7186: if (!dm->dmBC) {
7187: PetscSection newSection, gsection;
7188: PetscSF sf;
7190: DMClone(dm, &dm->dmBC);
7191: DMCopyDisc(dm, dm->dmBC);
7192: PetscSectionClone(section, &newSection);
7193: DMSetLocalSection(dm->dmBC, newSection);
7194: PetscSectionDestroy(&newSection);
7195: DMGetPointSF(dm->dmBC, &sf);
7196: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7197: DMSetGlobalSection(dm->dmBC, gsection);
7198: PetscSectionDestroy(&gsection);
7199: }
7200: *odm = dm->dmBC;
7201: return(0);
7202: }
7204: /*@
7205: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7207: Input Parameter:
7208: . dm - The original DM
7210: Output Parameters:
7211: + num - The output sequence number
7212: - val - The output sequence value
7214: Level: intermediate
7216: Note: This is intended for output that should appear in sequence, for instance
7217: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7219: .seealso: VecView()
7220: @*/
7221: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7222: {
7227: return(0);
7228: }
7230: /*@
7231: DMSetOutputSequenceNumber - Set the sequence number/value for output
7233: Input Parameters:
7234: + dm - The original DM
7235: . num - The output sequence number
7236: - val - The output sequence value
7238: Level: intermediate
7240: Note: This is intended for output that should appear in sequence, for instance
7241: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7243: .seealso: VecView()
7244: @*/
7245: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7246: {
7249: dm->outputSequenceNum = num;
7250: dm->outputSequenceVal = val;
7251: return(0);
7252: }
7254: /*@C
7255: DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7257: Input Parameters:
7258: + dm - The original DM
7259: . name - The sequence name
7260: - num - The output sequence number
7262: Output Parameter:
7263: . val - The output sequence value
7265: Level: intermediate
7267: Note: This is intended for output that should appear in sequence, for instance
7268: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7270: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7271: @*/
7272: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7273: {
7274: PetscBool ishdf5;
7281: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7282: if (ishdf5) {
7283: #if defined(PETSC_HAVE_HDF5)
7284: PetscScalar value;
7286: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7287: *val = PetscRealPart(value);
7288: #endif
7289: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7290: return(0);
7291: }
7293: /*@
7294: DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7296: Not collective
7298: Input Parameter:
7299: . dm - The DM
7301: Output Parameter:
7302: . useNatural - The flag to build the mapping to a natural order during distribution
7304: Level: beginner
7306: .seealso: DMSetUseNatural(), DMCreate()
7307: @*/
7308: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7309: {
7313: *useNatural = dm->useNatural;
7314: return(0);
7315: }
7317: /*@
7318: DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7320: Collective on dm
7322: Input Parameters:
7323: + dm - The DM
7324: - useNatural - The flag to build the mapping to a natural order during distribution
7326: Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7328: Level: beginner
7330: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7331: @*/
7332: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7333: {
7337: dm->useNatural = useNatural;
7338: return(0);
7339: }
7341: /*@C
7342: DMCreateLabel - Create a label of the given name if it does not already exist
7344: Not Collective
7346: Input Parameters:
7347: + dm - The DM object
7348: - name - The label name
7350: Level: intermediate
7352: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7353: @*/
7354: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7355: {
7356: PetscBool flg;
7357: DMLabel label;
7363: DMHasLabel(dm, name, &flg);
7364: if (!flg) {
7365: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7366: DMAddLabel(dm, label);
7367: DMLabelDestroy(&label);
7368: }
7369: return(0);
7370: }
7372: /*@C
7373: DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.
7375: Not Collective
7377: Input Parameters:
7378: + dm - The DM object
7379: . l - The index for the label
7380: - name - The label name
7382: Level: intermediate
7384: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7385: @*/
7386: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7387: {
7388: DMLabelLink orig, prev = NULL;
7389: DMLabel label;
7390: PetscInt Nl, m;
7391: PetscBool flg, match;
7392: const char *lname;
7398: DMHasLabel(dm, name, &flg);
7399: if (!flg) {
7400: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7401: DMAddLabel(dm, label);
7402: DMLabelDestroy(&label);
7403: }
7404: DMGetNumLabels(dm, &Nl);
7405: if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7406: for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7407: PetscObjectGetName((PetscObject) orig->label, &lname);
7408: PetscStrcmp(name, lname, &match);
7409: if (match) break;
7410: }
7411: if (m == l) return(0);
7412: if (!m) dm->labels = orig->next;
7413: else prev->next = orig->next;
7414: if (!l) {
7415: orig->next = dm->labels;
7416: dm->labels = orig;
7417: } else {
7418: for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7419: orig->next = prev->next;
7420: prev->next = orig;
7421: }
7422: return(0);
7423: }
7425: /*@C
7426: DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7428: Not Collective
7430: Input Parameters:
7431: + dm - The DM object
7432: . name - The label name
7433: - point - The mesh point
7435: Output Parameter:
7436: . value - The label value for this point, or -1 if the point is not in the label
7438: Level: beginner
7440: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7441: @*/
7442: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7443: {
7444: DMLabel label;
7450: DMGetLabel(dm, name, &label);
7451: if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7452: DMLabelGetValue(label, point, value);
7453: return(0);
7454: }
7456: /*@C
7457: DMSetLabelValue - Add a point to a Sieve Label with given value
7459: Not Collective
7461: Input Parameters:
7462: + dm - The DM object
7463: . name - The label name
7464: . point - The mesh point
7465: - value - The label value for this point
7467: Output Parameter:
7469: Level: beginner
7471: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7472: @*/
7473: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7474: {
7475: DMLabel label;
7481: DMGetLabel(dm, name, &label);
7482: if (!label) {
7483: DMCreateLabel(dm, name);
7484: DMGetLabel(dm, name, &label);
7485: }
7486: DMLabelSetValue(label, point, value);
7487: return(0);
7488: }
7490: /*@C
7491: DMClearLabelValue - Remove a point from a Sieve Label with given value
7493: Not Collective
7495: Input Parameters:
7496: + dm - The DM object
7497: . name - The label name
7498: . point - The mesh point
7499: - value - The label value for this point
7501: Output Parameter:
7503: Level: beginner
7505: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7506: @*/
7507: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7508: {
7509: DMLabel label;
7515: DMGetLabel(dm, name, &label);
7516: if (!label) return(0);
7517: DMLabelClearValue(label, point, value);
7518: return(0);
7519: }
7521: /*@C
7522: DMGetLabelSize - Get the number of different integer ids in a Label
7524: Not Collective
7526: Input Parameters:
7527: + dm - The DM object
7528: - name - The label name
7530: Output Parameter:
7531: . size - The number of different integer ids, or 0 if the label does not exist
7533: Level: beginner
7535: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7536: @*/
7537: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7538: {
7539: DMLabel label;
7546: DMGetLabel(dm, name, &label);
7547: *size = 0;
7548: if (!label) return(0);
7549: DMLabelGetNumValues(label, size);
7550: return(0);
7551: }
7553: /*@C
7554: DMGetLabelIdIS - Get the integer ids in a label
7556: Not Collective
7558: Input Parameters:
7559: + mesh - The DM object
7560: - name - The label name
7562: Output Parameter:
7563: . ids - The integer ids, or NULL if the label does not exist
7565: Level: beginner
7567: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7568: @*/
7569: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7570: {
7571: DMLabel label;
7578: DMGetLabel(dm, name, &label);
7579: *ids = NULL;
7580: if (label) {
7581: DMLabelGetValueIS(label, ids);
7582: } else {
7583: /* returning an empty IS */
7584: ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7585: }
7586: return(0);
7587: }
7589: /*@C
7590: DMGetStratumSize - Get the number of points in a label stratum
7592: Not Collective
7594: Input Parameters:
7595: + dm - The DM object
7596: . name - The label name
7597: - value - The stratum value
7599: Output Parameter:
7600: . size - The stratum size
7602: Level: beginner
7604: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7605: @*/
7606: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7607: {
7608: DMLabel label;
7615: DMGetLabel(dm, name, &label);
7616: *size = 0;
7617: if (!label) return(0);
7618: DMLabelGetStratumSize(label, value, size);
7619: return(0);
7620: }
7622: /*@C
7623: DMGetStratumIS - Get the points in a label stratum
7625: Not Collective
7627: Input Parameters:
7628: + dm - The DM object
7629: . name - The label name
7630: - value - The stratum value
7632: Output Parameter:
7633: . points - The stratum points, or NULL if the label does not exist or does not have that value
7635: Level: beginner
7637: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7638: @*/
7639: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7640: {
7641: DMLabel label;
7648: DMGetLabel(dm, name, &label);
7649: *points = NULL;
7650: if (!label) return(0);
7651: DMLabelGetStratumIS(label, value, points);
7652: return(0);
7653: }
7655: /*@C
7656: DMSetStratumIS - Set the points in a label stratum
7658: Not Collective
7660: Input Parameters:
7661: + dm - The DM object
7662: . name - The label name
7663: . value - The stratum value
7664: - points - The stratum points
7666: Level: beginner
7668: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7669: @*/
7670: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7671: {
7672: DMLabel label;
7679: DMGetLabel(dm, name, &label);
7680: if (!label) return(0);
7681: DMLabelSetStratumIS(label, value, points);
7682: return(0);
7683: }
7685: /*@C
7686: DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7688: Not Collective
7690: Input Parameters:
7691: + dm - The DM object
7692: . name - The label name
7693: - value - The label value for this point
7695: Output Parameter:
7697: Level: beginner
7699: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7700: @*/
7701: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7702: {
7703: DMLabel label;
7709: DMGetLabel(dm, name, &label);
7710: if (!label) return(0);
7711: DMLabelClearStratum(label, value);
7712: return(0);
7713: }
7715: /*@
7716: DMGetNumLabels - Return the number of labels defined by the mesh
7718: Not Collective
7720: Input Parameter:
7721: . dm - The DM object
7723: Output Parameter:
7724: . numLabels - the number of Labels
7726: Level: intermediate
7728: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7729: @*/
7730: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7731: {
7732: DMLabelLink next = dm->labels;
7733: PetscInt n = 0;
7738: while (next) {++n; next = next->next;}
7739: *numLabels = n;
7740: return(0);
7741: }
7743: /*@C
7744: DMGetLabelName - Return the name of nth label
7746: Not Collective
7748: Input Parameters:
7749: + dm - The DM object
7750: - n - the label number
7752: Output Parameter:
7753: . name - the label name
7755: Level: intermediate
7757: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7758: @*/
7759: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7760: {
7761: DMLabelLink next = dm->labels;
7762: PetscInt l = 0;
7768: while (next) {
7769: if (l == n) {
7770: PetscObjectGetName((PetscObject) next->label, name);
7771: return(0);
7772: }
7773: ++l;
7774: next = next->next;
7775: }
7776: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7777: }
7779: /*@C
7780: DMHasLabel - Determine whether the mesh has a label of a given name
7782: Not Collective
7784: Input Parameters:
7785: + dm - The DM object
7786: - name - The label name
7788: Output Parameter:
7789: . hasLabel - PETSC_TRUE if the label is present
7791: Level: intermediate
7793: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7794: @*/
7795: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7796: {
7797: DMLabelLink next = dm->labels;
7798: const char *lname;
7805: *hasLabel = PETSC_FALSE;
7806: while (next) {
7807: PetscObjectGetName((PetscObject) next->label, &lname);
7808: PetscStrcmp(name, lname, hasLabel);
7809: if (*hasLabel) break;
7810: next = next->next;
7811: }
7812: return(0);
7813: }
7815: /*@C
7816: DMGetLabel - Return the label of a given name, or NULL
7818: Not Collective
7820: Input Parameters:
7821: + dm - The DM object
7822: - name - The label name
7824: Output Parameter:
7825: . label - The DMLabel, or NULL if the label is absent
7827: Note: Some of the default labels in a DMPlex will be
7828: $ "depth" - Holds the depth (co-dimension) of each mesh point
7829: $ "celltype" - Holds the topological type of each cell
7830: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7831: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7832: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7833: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7835: Level: intermediate
7837: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7838: @*/
7839: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7840: {
7841: DMLabelLink next = dm->labels;
7842: PetscBool hasLabel;
7843: const char *lname;
7850: *label = NULL;
7851: while (next) {
7852: PetscObjectGetName((PetscObject) next->label, &lname);
7853: PetscStrcmp(name, lname, &hasLabel);
7854: if (hasLabel) {
7855: *label = next->label;
7856: break;
7857: }
7858: next = next->next;
7859: }
7860: return(0);
7861: }
7863: /*@C
7864: DMGetLabelByNum - Return the nth label
7866: Not Collective
7868: Input Parameters:
7869: + dm - The DM object
7870: - n - the label number
7872: Output Parameter:
7873: . label - the label
7875: Level: intermediate
7877: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7878: @*/
7879: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7880: {
7881: DMLabelLink next = dm->labels;
7882: PetscInt l = 0;
7887: while (next) {
7888: if (l == n) {
7889: *label = next->label;
7890: return(0);
7891: }
7892: ++l;
7893: next = next->next;
7894: }
7895: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7896: }
7898: /*@C
7899: DMAddLabel - Add the label to this mesh
7901: Not Collective
7903: Input Parameters:
7904: + dm - The DM object
7905: - label - The DMLabel
7907: Level: developer
7909: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7910: @*/
7911: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7912: {
7913: DMLabelLink l, *p, tmpLabel;
7914: PetscBool hasLabel;
7915: const char *lname;
7916: PetscBool flg;
7921: PetscObjectGetName((PetscObject) label, &lname);
7922: DMHasLabel(dm, lname, &hasLabel);
7923: if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7924: PetscCalloc1(1, &tmpLabel);
7925: tmpLabel->label = label;
7926: tmpLabel->output = PETSC_TRUE;
7927: for (p=&dm->labels; (l=*p); p=&l->next) {}
7928: *p = tmpLabel;
7929: PetscObjectReference((PetscObject)label);
7930: PetscStrcmp(lname, "depth", &flg);
7931: if (flg) dm->depthLabel = label;
7932: PetscStrcmp(lname, "celltype", &flg);
7933: if (flg) dm->celltypeLabel = label;
7934: return(0);
7935: }
7937: /*@C
7938: DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7940: Not Collective
7942: Input Parameters:
7943: + dm - The DM object
7944: - label - The DMLabel, having the same name, to substitute
7946: Note: Some of the default labels in a DMPlex will be
7947: $ "depth" - Holds the depth (co-dimension) of each mesh point
7948: $ "celltype" - Holds the topological type of each cell
7949: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7950: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7951: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7952: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7954: Level: intermediate
7956: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7957: @*/
7958: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7959: {
7960: DMLabelLink next = dm->labels;
7961: PetscBool hasLabel, flg;
7962: const char *name, *lname;
7968: PetscObjectGetName((PetscObject) label, &name);
7969: while (next) {
7970: PetscObjectGetName((PetscObject) next->label, &lname);
7971: PetscStrcmp(name, lname, &hasLabel);
7972: if (hasLabel) {
7973: PetscObjectReference((PetscObject) label);
7974: PetscStrcmp(lname, "depth", &flg);
7975: if (flg) dm->depthLabel = label;
7976: PetscStrcmp(lname, "celltype", &flg);
7977: if (flg) dm->celltypeLabel = label;
7978: DMLabelDestroy(&next->label);
7979: next->label = label;
7980: break;
7981: }
7982: next = next->next;
7983: }
7984: return(0);
7985: }
7987: /*@C
7988: DMRemoveLabel - Remove the label given by name from this mesh
7990: Not Collective
7992: Input Parameters:
7993: + dm - The DM object
7994: - name - The label name
7996: Output Parameter:
7997: . label - The DMLabel, or NULL if the label is absent
7999: Level: developer
8001: Notes:
8002: DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
8003: DMLabelDestroy() on the label.
8005: DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
8006: call DMLabelDestroy(). Instead, the label is returned and the user is
8007: responsible of calling DMLabelDestroy() at some point.
8009: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
8010: @*/
8011: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8012: {
8013: DMLabelLink link, *pnext;
8014: PetscBool hasLabel;
8015: const char *lname;
8021: if (label) {
8023: *label = NULL;
8024: }
8025: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8026: PetscObjectGetName((PetscObject) link->label, &lname);
8027: PetscStrcmp(name, lname, &hasLabel);
8028: if (hasLabel) {
8029: *pnext = link->next; /* Remove from list */
8030: PetscStrcmp(name, "depth", &hasLabel);
8031: if (hasLabel) dm->depthLabel = NULL;
8032: PetscStrcmp(name, "celltype", &hasLabel);
8033: if (hasLabel) dm->celltypeLabel = NULL;
8034: if (label) *label = link->label;
8035: else {DMLabelDestroy(&link->label);}
8036: PetscFree(link);
8037: break;
8038: }
8039: }
8040: return(0);
8041: }
8043: /*@
8044: DMRemoveLabelBySelf - Remove the label from this mesh
8046: Not Collective
8048: Input Parameters:
8049: + dm - The DM object
8050: . label - The DMLabel to be removed from the DM
8051: - failNotFound - Should it fail if the label is not found in the DM?
8053: Level: developer
8055: Notes:
8056: Only exactly the same instance is removed if found, name match is ignored.
8057: If the DM has an exclusive reference to the label, it gets destroyed and
8058: *label nullified.
8060: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
8061: @*/
8062: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8063: {
8064: DMLabelLink link, *pnext;
8065: PetscBool hasLabel = PETSC_FALSE;
8071: if (!*label && !failNotFound) return(0);
8074: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8075: if (*label == link->label) {
8076: hasLabel = PETSC_TRUE;
8077: *pnext = link->next; /* Remove from list */
8078: if (*label == dm->depthLabel) dm->depthLabel = NULL;
8079: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8080: if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8081: DMLabelDestroy(&link->label);
8082: PetscFree(link);
8083: break;
8084: }
8085: }
8086: if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8087: return(0);
8088: }
8090: /*@C
8091: DMGetLabelOutput - Get the output flag for a given label
8093: Not Collective
8095: Input Parameters:
8096: + dm - The DM object
8097: - name - The label name
8099: Output Parameter:
8100: . output - The flag for output
8102: Level: developer
8104: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8105: @*/
8106: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8107: {
8108: DMLabelLink next = dm->labels;
8109: const char *lname;
8116: while (next) {
8117: PetscBool flg;
8119: PetscObjectGetName((PetscObject) next->label, &lname);
8120: PetscStrcmp(name, lname, &flg);
8121: if (flg) {*output = next->output; return(0);}
8122: next = next->next;
8123: }
8124: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8125: }
8127: /*@C
8128: DMSetLabelOutput - Set the output flag for a given label
8130: Not Collective
8132: Input Parameters:
8133: + dm - The DM object
8134: . name - The label name
8135: - output - The flag for output
8137: Level: developer
8139: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8140: @*/
8141: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8142: {
8143: DMLabelLink next = dm->labels;
8144: const char *lname;
8150: while (next) {
8151: PetscBool flg;
8153: PetscObjectGetName((PetscObject) next->label, &lname);
8154: PetscStrcmp(name, lname, &flg);
8155: if (flg) {next->output = output; return(0);}
8156: next = next->next;
8157: }
8158: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8159: }
8161: /*@
8162: DMCopyLabels - Copy labels from one mesh to another with a superset of the points
8164: Collective on dmA
8166: Input Parameters:
8167: + dmA - The DM object with initial labels
8168: . dmB - The DM object with copied labels
8169: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8170: - all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8172: Level: intermediate
8174: Note: This is typically used when interpolating or otherwise adding to a mesh
8176: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8177: @*/
8178: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8179: {
8180: DMLabel label, labelNew;
8181: const char *name;
8182: PetscBool flg;
8183: DMLabelLink link;
8191: if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8192: if (dmA == dmB) return(0);
8193: for (link=dmA->labels; link; link=link->next) {
8194: label=link->label;
8195: PetscObjectGetName((PetscObject)label, &name);
8196: if (!all) {
8197: PetscStrcmp(name, "depth", &flg);
8198: if (flg) continue;
8199: PetscStrcmp(name, "dim", &flg);
8200: if (flg) continue;
8201: PetscStrcmp(name, "celltype", &flg);
8202: if (flg) continue;
8203: }
8204: if (mode==PETSC_COPY_VALUES) {
8205: DMLabelDuplicate(label, &labelNew);
8206: } else {
8207: labelNew = label;
8208: }
8209: DMAddLabel(dmB, labelNew);
8210: if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8211: }
8212: return(0);
8213: }
8215: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8216: {
8220: if (!*label) {
8221: DMCreateLabel(dm, name);
8222: DMGetLabel(dm, name, label);
8223: }
8224: DMLabelSetValue(*label, point, value);
8225: return(0);
8226: }
8228: /*
8229: Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8230: like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8231: (label, id) pair in the DM.
8233: However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8234: each label.
8235: */
8236: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8237: {
8238: DMUniversalLabel ul;
8239: PetscBool *active;
8240: PetscInt pStart, pEnd, p, Nl, l, m;
8241: PetscErrorCode ierr;
8244: PetscMalloc1(1, &ul);
8245: DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8246: DMGetNumLabels(dm, &Nl);
8247: PetscCalloc1(Nl, &active);
8248: ul->Nl = 0;
8249: for (l = 0; l < Nl; ++l) {
8250: PetscBool isdepth, iscelltype;
8251: const char *name;
8253: DMGetLabelName(dm, l, &name);
8254: PetscStrncmp(name, "depth", 6, &isdepth);
8255: PetscStrncmp(name, "celltype", 9, &iscelltype);
8256: active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8257: if (active[l]) ++ul->Nl;
8258: }
8259: PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8260: ul->Nv = 0;
8261: for (l = 0, m = 0; l < Nl; ++l) {
8262: DMLabel label;
8263: PetscInt nv;
8264: const char *name;
8266: if (!active[l]) continue;
8267: DMGetLabelName(dm, l, &name);
8268: DMGetLabelByNum(dm, l, &label);
8269: DMLabelGetNumValues(label, &nv);
8270: PetscStrallocpy(name, &ul->names[m]);
8271: ul->indices[m] = l;
8272: ul->Nv += nv;
8273: ul->offsets[m+1] = nv;
8274: ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1));
8275: ++m;
8276: }
8277: for (l = 1; l <= ul->Nl; ++l) {
8278: ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8279: ul->bits[l] = ul->bits[l-1] + ul->bits[l];
8280: }
8281: for (l = 0; l < ul->Nl; ++l) {
8282: PetscInt b;
8284: ul->masks[l] = 0;
8285: for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8286: }
8287: PetscMalloc1(ul->Nv, &ul->values);
8288: for (l = 0, m = 0; l < Nl; ++l) {
8289: DMLabel label;
8290: IS valueIS;
8291: const PetscInt *varr;
8292: PetscInt nv, v;
8294: if (!active[l]) continue;
8295: DMGetLabelByNum(dm, l, &label);
8296: DMLabelGetNumValues(label, &nv);
8297: DMLabelGetValueIS(label, &valueIS);
8298: ISGetIndices(valueIS, &varr);
8299: for (v = 0; v < nv; ++v) {
8300: ul->values[ul->offsets[m]+v] = varr[v];
8301: }
8302: ISRestoreIndices(valueIS, &varr);
8303: ISDestroy(&valueIS);
8304: PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8305: ++m;
8306: }
8307: DMPlexGetChart(dm, &pStart, &pEnd);
8308: for (p = pStart; p < pEnd; ++p) {
8309: PetscInt uval = 0;
8310: PetscBool marked = PETSC_FALSE;
8312: for (l = 0, m = 0; l < Nl; ++l) {
8313: DMLabel label;
8314: PetscInt val, defval, loc, nv;
8316: if (!active[l]) continue;
8317: DMGetLabelByNum(dm, l, &label);
8318: DMLabelGetValue(label, p, &val);
8319: DMLabelGetDefaultValue(label, &defval);
8320: if (val == defval) {++m; continue;}
8321: nv = ul->offsets[m+1]-ul->offsets[m];
8322: marked = PETSC_TRUE;
8323: PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8324: if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8325: uval += (loc+1) << ul->bits[m];
8326: ++m;
8327: }
8328: if (marked) {DMLabelSetValue(ul->label, p, uval);}
8329: }
8330: PetscFree(active);
8331: *universal = ul;
8332: return(0);
8333: }
8335: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8336: {
8337: PetscInt l;
8341: for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8342: DMLabelDestroy(&(*universal)->label);
8343: PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8344: PetscFree((*universal)->values);
8345: PetscFree(*universal);
8346: *universal = NULL;
8347: return(0);
8348: }
8350: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8351: {
8354: *ulabel = ul->label;
8355: return(0);
8356: }
8358: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8359: {
8360: PetscInt Nl = ul->Nl, l;
8365: for (l = 0; l < Nl; ++l) {
8366: if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8367: else {DMCreateLabel(dm, ul->names[l]);}
8368: }
8369: if (preserveOrder) {
8370: for (l = 0; l < ul->Nl; ++l) {
8371: const char *name;
8372: PetscBool match;
8374: DMGetLabelName(dm, ul->indices[l], &name);
8375: PetscStrcmp(name, ul->names[l], &match);
8376: if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8377: }
8378: }
8379: return(0);
8380: }
8382: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8383: {
8384: PetscInt l;
8388: for (l = 0; l < ul->Nl; ++l) {
8389: DMLabel label;
8390: PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8392: if (lval) {
8393: if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8394: else {DMGetLabel(dm, ul->names[l], &label);}
8395: DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8396: }
8397: }
8398: return(0);
8399: }
8401: /*@
8402: DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8404: Input Parameter:
8405: . dm - The DM object
8407: Output Parameter:
8408: . cdm - The coarse DM
8410: Level: intermediate
8412: .seealso: DMSetCoarseDM()
8413: @*/
8414: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8415: {
8419: *cdm = dm->coarseMesh;
8420: return(0);
8421: }
8423: /*@
8424: DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8426: Input Parameters:
8427: + dm - The DM object
8428: - cdm - The coarse DM
8430: Level: intermediate
8432: .seealso: DMGetCoarseDM()
8433: @*/
8434: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8435: {
8441: PetscObjectReference((PetscObject)cdm);
8442: DMDestroy(&dm->coarseMesh);
8443: dm->coarseMesh = cdm;
8444: return(0);
8445: }
8447: /*@
8448: DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8450: Input Parameter:
8451: . dm - The DM object
8453: Output Parameter:
8454: . fdm - The fine DM
8456: Level: intermediate
8458: .seealso: DMSetFineDM()
8459: @*/
8460: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8461: {
8465: *fdm = dm->fineMesh;
8466: return(0);
8467: }
8469: /*@
8470: DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8472: Input Parameters:
8473: + dm - The DM object
8474: - fdm - The fine DM
8476: Level: intermediate
8478: .seealso: DMGetFineDM()
8479: @*/
8480: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8481: {
8487: PetscObjectReference((PetscObject)fdm);
8488: DMDestroy(&dm->fineMesh);
8489: dm->fineMesh = fdm;
8490: return(0);
8491: }
8493: /*=== DMBoundary code ===*/
8495: /*@C
8496: DMAddBoundary - Add a boundary condition to the model
8498: Collective on dm
8500: Input Parameters:
8501: + dm - The DM, with a PetscDS that matches the problem being constrained
8502: . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8503: . name - The BC name
8504: . label - The label defining constrained points
8505: . Nv - The number of DMLabel values for constrained points
8506: . values - An array of values for constrained points
8507: . field - The field to constrain
8508: . Nc - The number of constrained field components (0 will constrain all fields)
8509: . comps - An array of constrained component numbers
8510: . bcFunc - A pointwise function giving boundary values
8511: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8512: - ctx - An optional user context for bcFunc
8514: Output Parameter:
8515: . bd - (Optional) Boundary number
8517: Options Database Keys:
8518: + -bc_<boundary name> <num> - Overrides the boundary ids
8519: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8521: Note:
8522: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8524: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8526: If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8528: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8529: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8530: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8531: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
8533: + dim - the spatial dimension
8534: . Nf - the number of fields
8535: . uOff - the offset into u[] and u_t[] for each field
8536: . uOff_x - the offset into u_x[] for each field
8537: . u - each field evaluated at the current point
8538: . u_t - the time derivative of each field evaluated at the current point
8539: . u_x - the gradient of each field evaluated at the current point
8540: . aOff - the offset into a[] and a_t[] for each auxiliary field
8541: . aOff_x - the offset into a_x[] for each auxiliary field
8542: . a - each auxiliary field evaluated at the current point
8543: . a_t - the time derivative of each auxiliary field evaluated at the current point
8544: . a_x - the gradient of auxiliary each field evaluated at the current point
8545: . t - current time
8546: . x - coordinates of the current point
8547: . numConstants - number of constant parameters
8548: . constants - constant parameters
8549: - bcval - output values at the current point
8551: Level: developer
8553: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8554: @*/
8555: 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)
8556: {
8557: PetscDS ds;
8567: DMGetDS(dm, &ds);
8568: DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8569: PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8570: return(0);
8571: }
8573: /* TODO Remove this since now the structures are the same */
8574: static PetscErrorCode DMPopulateBoundary(DM dm)
8575: {
8576: PetscDS ds;
8577: DMBoundary *lastnext;
8578: DSBoundary dsbound;
8582: DMGetDS(dm, &ds);
8583: dsbound = ds->boundary;
8584: if (dm->boundary) {
8585: DMBoundary next = dm->boundary;
8587: /* quick check to see if the PetscDS has changed */
8588: if (next->dsboundary == dsbound) return(0);
8589: /* the PetscDS has changed: tear down and rebuild */
8590: while (next) {
8591: DMBoundary b = next;
8593: next = b->next;
8594: PetscFree(b);
8595: }
8596: dm->boundary = NULL;
8597: }
8599: lastnext = &(dm->boundary);
8600: while (dsbound) {
8601: DMBoundary dmbound;
8603: PetscNew(&dmbound);
8604: dmbound->dsboundary = dsbound;
8605: dmbound->label = dsbound->label;
8606: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8607: *lastnext = dmbound;
8608: lastnext = &(dmbound->next);
8609: dsbound = dsbound->next;
8610: }
8611: return(0);
8612: }
8614: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8615: {
8616: DMBoundary b;
8622: *isBd = PETSC_FALSE;
8623: DMPopulateBoundary(dm);
8624: b = dm->boundary;
8625: while (b && !(*isBd)) {
8626: DMLabel label = b->label;
8627: DSBoundary dsb = b->dsboundary;
8628: PetscInt i;
8630: if (label) {
8631: for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
8632: }
8633: b = b->next;
8634: }
8635: return(0);
8636: }
8638: /*@C
8639: DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8641: Collective on DM
8643: Input Parameters:
8644: + dm - The DM
8645: . time - The time
8646: . funcs - The coordinate functions to evaluate, one per field
8647: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8648: - mode - The insertion mode for values
8650: Output Parameter:
8651: . X - vector
8653: Calling sequence of func:
8654: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8656: + dim - The spatial dimension
8657: . time - The time at which to sample
8658: . x - The coordinates
8659: . Nc - The number of components
8660: . u - The output field values
8661: - ctx - optional user-defined function context
8663: Level: developer
8665: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8666: @*/
8667: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8668: {
8669: Vec localX;
8674: DMGetLocalVector(dm, &localX);
8675: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8676: DMLocalToGlobalBegin(dm, localX, mode, X);
8677: DMLocalToGlobalEnd(dm, localX, mode, X);
8678: DMRestoreLocalVector(dm, &localX);
8679: return(0);
8680: }
8682: /*@C
8683: DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8685: Not collective
8687: Input Parameters:
8688: + dm - The DM
8689: . time - The time
8690: . funcs - The coordinate functions to evaluate, one per field
8691: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8692: - mode - The insertion mode for values
8694: Output Parameter:
8695: . localX - vector
8697: Calling sequence of func:
8698: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8700: + dim - The spatial dimension
8701: . x - The coordinates
8702: . Nc - The number of components
8703: . u - The output field values
8704: - ctx - optional user-defined function context
8706: Level: developer
8708: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8709: @*/
8710: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8711: {
8717: if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8718: (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8719: return(0);
8720: }
8722: /*@C
8723: 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.
8725: Collective on DM
8727: Input Parameters:
8728: + dm - The DM
8729: . time - The time
8730: . label - The DMLabel selecting the portion of the mesh for projection
8731: . funcs - The coordinate functions to evaluate, one per field
8732: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8733: - mode - The insertion mode for values
8735: Output Parameter:
8736: . X - vector
8738: Calling sequence of func:
8739: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8741: + dim - The spatial dimension
8742: . x - The coordinates
8743: . Nc - The number of components
8744: . u - The output field values
8745: - ctx - optional user-defined function context
8747: Level: developer
8749: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8750: @*/
8751: 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)
8752: {
8753: Vec localX;
8758: DMGetLocalVector(dm, &localX);
8759: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8760: DMLocalToGlobalBegin(dm, localX, mode, X);
8761: DMLocalToGlobalEnd(dm, localX, mode, X);
8762: DMRestoreLocalVector(dm, &localX);
8763: return(0);
8764: }
8766: /*@C
8767: 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.
8769: Not collective
8771: Input Parameters:
8772: + dm - The DM
8773: . time - The time
8774: . label - The DMLabel selecting the portion of the mesh for projection
8775: . funcs - The coordinate functions to evaluate, one per field
8776: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8777: - mode - The insertion mode for values
8779: Output Parameter:
8780: . localX - vector
8782: Calling sequence of func:
8783: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8785: + dim - The spatial dimension
8786: . x - The coordinates
8787: . Nc - The number of components
8788: . u - The output field values
8789: - ctx - optional user-defined function context
8791: Level: developer
8793: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8794: @*/
8795: 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)
8796: {
8802: if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8803: (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8804: return(0);
8805: }
8807: /*@C
8808: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8810: Not collective
8812: Input Parameters:
8813: + dm - The DM
8814: . time - The time
8815: . localU - The input field vector
8816: . funcs - The functions to evaluate, one per field
8817: - mode - The insertion mode for values
8819: Output Parameter:
8820: . localX - The output vector
8822: Calling sequence of func:
8823: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8824: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8825: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8826: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8828: + dim - The spatial dimension
8829: . Nf - The number of input fields
8830: . NfAux - The number of input auxiliary fields
8831: . uOff - The offset of each field in u[]
8832: . uOff_x - The offset of each field in u_x[]
8833: . u - The field values at this point in space
8834: . u_t - The field time derivative at this point in space (or NULL)
8835: . u_x - The field derivatives at this point in space
8836: . aOff - The offset of each auxiliary field in u[]
8837: . aOff_x - The offset of each auxiliary field in u_x[]
8838: . a - The auxiliary field values at this point in space
8839: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8840: . a_x - The auxiliary field derivatives at this point in space
8841: . t - The current time
8842: . x - The coordinates of this point
8843: . numConstants - The number of constants
8844: . constants - The value of each constant
8845: - f - The value of the function at this point in space
8847: 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.
8848: 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
8849: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8850: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8852: Level: intermediate
8854: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8855: @*/
8856: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8857: void (**funcs)(PetscInt, PetscInt, PetscInt,
8858: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8859: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8860: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8861: InsertMode mode, Vec localX)
8862: {
8869: if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8870: (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8871: return(0);
8872: }
8874: /*@C
8875: 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.
8877: Not collective
8879: Input Parameters:
8880: + dm - The DM
8881: . time - The time
8882: . label - The DMLabel marking the portion of the domain to output
8883: . numIds - The number of label ids to use
8884: . ids - The label ids to use for marking
8885: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8886: . comps - The components to set in the output, or NULL for all components
8887: . localU - The input field vector
8888: . funcs - The functions to evaluate, one per field
8889: - mode - The insertion mode for values
8891: Output Parameter:
8892: . localX - The output vector
8894: Calling sequence of func:
8895: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8896: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8897: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8898: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8900: + dim - The spatial dimension
8901: . Nf - The number of input fields
8902: . NfAux - The number of input auxiliary fields
8903: . uOff - The offset of each field in u[]
8904: . uOff_x - The offset of each field in u_x[]
8905: . u - The field values at this point in space
8906: . u_t - The field time derivative at this point in space (or NULL)
8907: . u_x - The field derivatives at this point in space
8908: . aOff - The offset of each auxiliary field in u[]
8909: . aOff_x - The offset of each auxiliary field in u_x[]
8910: . a - The auxiliary field values at this point in space
8911: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8912: . a_x - The auxiliary field derivatives at this point in space
8913: . t - The current time
8914: . x - The coordinates of this point
8915: . numConstants - The number of constants
8916: . constants - The value of each constant
8917: - f - The value of the function at this point in space
8919: 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.
8920: 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
8921: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8922: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8924: Level: intermediate
8926: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8927: @*/
8928: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8929: void (**funcs)(PetscInt, PetscInt, PetscInt,
8930: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8931: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8932: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8933: InsertMode mode, Vec localX)
8934: {
8941: if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8942: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8943: return(0);
8944: }
8946: /*@C
8947: 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.
8949: Not collective
8951: Input Parameters:
8952: + dm - The DM
8953: . time - The time
8954: . label - The DMLabel marking the portion of the domain boundary to output
8955: . numIds - The number of label ids to use
8956: . ids - The label ids to use for marking
8957: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8958: . comps - The components to set in the output, or NULL for all components
8959: . localU - The input field vector
8960: . funcs - The functions to evaluate, one per field
8961: - mode - The insertion mode for values
8963: Output Parameter:
8964: . localX - The output vector
8966: Calling sequence of func:
8967: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8968: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8969: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8970: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8972: + dim - The spatial dimension
8973: . Nf - The number of input fields
8974: . NfAux - The number of input auxiliary fields
8975: . uOff - The offset of each field in u[]
8976: . uOff_x - The offset of each field in u_x[]
8977: . u - The field values at this point in space
8978: . u_t - The field time derivative at this point in space (or NULL)
8979: . u_x - The field derivatives at this point in space
8980: . aOff - The offset of each auxiliary field in u[]
8981: . aOff_x - The offset of each auxiliary field in u_x[]
8982: . a - The auxiliary field values at this point in space
8983: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8984: . a_x - The auxiliary field derivatives at this point in space
8985: . t - The current time
8986: . x - The coordinates of this point
8987: . n - The face normal
8988: . numConstants - The number of constants
8989: . constants - The value of each constant
8990: - f - The value of the function at this point in space
8992: Note:
8993: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8994: 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
8995: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8996: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8998: Level: intermediate
9000: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
9001: @*/
9002: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9003: void (**funcs)(PetscInt, PetscInt, PetscInt,
9004: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9005: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9006: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9007: InsertMode mode, Vec localX)
9008: {
9015: if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9016: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
9017: return(0);
9018: }
9020: /*@C
9021: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9023: Input Parameters:
9024: + dm - The DM
9025: . time - The time
9026: . funcs - The functions to evaluate for each field component
9027: . ctxs - Optional array of contexts to pass to each function, or NULL.
9028: - X - The coefficient vector u_h, a global vector
9030: Output Parameter:
9031: . diff - The diff ||u - u_h||_2
9033: Level: developer
9035: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9036: @*/
9037: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
9038: {
9044: if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9045: (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
9046: return(0);
9047: }
9049: /*@C
9050: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
9052: Collective on dm
9054: Input Parameters:
9055: + dm - The DM
9056: , time - The time
9057: . funcs - The gradient functions to evaluate for each field component
9058: . ctxs - Optional array of contexts to pass to each function, or NULL.
9059: . X - The coefficient vector u_h, a global vector
9060: - n - The vector to project along
9062: Output Parameter:
9063: . diff - The diff ||(grad u - grad u_h) . n||_2
9065: Level: developer
9067: .seealso: DMProjectFunction(), DMComputeL2Diff()
9068: @*/
9069: 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)
9070: {
9076: if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9077: (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
9078: return(0);
9079: }
9081: /*@C
9082: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
9084: Collective on dm
9086: Input Parameters:
9087: + dm - The DM
9088: . time - The time
9089: . funcs - The functions to evaluate for each field component
9090: . ctxs - Optional array of contexts to pass to each function, or NULL.
9091: - X - The coefficient vector u_h, a global vector
9093: Output Parameter:
9094: . diff - The array of differences, ||u^f - u^f_h||_2
9096: Level: developer
9098: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9099: @*/
9100: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9101: {
9107: if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9108: (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9109: return(0);
9110: }
9112: /*@C
9113: DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags. Specific implementations of DM maybe have
9114: specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
9116: Collective on dm
9118: Input parameters:
9119: + dm - the pre-adaptation DM object
9120: - label - label with the flags
9122: Output parameters:
9123: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
9125: Level: intermediate
9127: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9128: @*/
9129: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9130: {
9137: *dmAdapt = NULL;
9138: if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9139: (dm->ops->adaptlabel)(dm, label, dmAdapt);
9140: if (*dmAdapt) {
9141: (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
9142: PetscFree((*dmAdapt)->vectype);
9143: PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9144: PetscFree((*dmAdapt)->mattype);
9145: PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9146: }
9147: return(0);
9148: }
9150: /*@C
9151: DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
9153: Input Parameters:
9154: + dm - The DM object
9155: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9156: - bdLabel - Label for boundary tags, which will be preserved in the output mesh. bdLabel should be NULL if there is no such label, and should be different from "_boundary_".
9158: Output Parameter:
9159: . dmAdapt - Pointer to the DM object containing the adapted mesh
9161: Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
9163: Level: advanced
9165: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9166: @*/
9167: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9168: {
9176: *dmAdapt = NULL;
9177: if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9178: (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9179: return(0);
9180: }
9182: /*@C
9183: DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9185: Not Collective
9187: Input Parameter:
9188: . dm - The DM
9190: Output Parameters:
9191: + nranks - the number of neighbours
9192: - ranks - the neighbors ranks
9194: Notes:
9195: Do not free the array, it is freed when the DM is destroyed.
9197: Level: beginner
9199: .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9200: @*/
9201: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9202: {
9207: if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9208: (dm->ops->getneighbors)(dm,nranks,ranks);
9209: return(0);
9210: }
9212: #include <petsc/private/matimpl.h>
9214: /*
9215: Converts the input vector to a ghosted vector and then calls the standard coloring code.
9216: This has be a different function because it requires DM which is not defined in the Mat library
9217: */
9218: PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9219: {
9223: if (coloring->ctype == IS_COLORING_LOCAL) {
9224: Vec x1local;
9225: DM dm;
9226: MatGetDM(J,&dm);
9227: if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9228: DMGetLocalVector(dm,&x1local);
9229: DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9230: DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9231: x1 = x1local;
9232: }
9233: MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9234: if (coloring->ctype == IS_COLORING_LOCAL) {
9235: DM dm;
9236: MatGetDM(J,&dm);
9237: DMRestoreLocalVector(dm,&x1);
9238: }
9239: return(0);
9240: }
9242: /*@
9243: MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9245: Input Parameter:
9246: . coloring - the MatFDColoring object
9248: Developer Notes:
9249: this routine exists because the PETSc Mat library does not know about the DM objects
9251: Level: advanced
9253: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9254: @*/
9255: PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9256: {
9258: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9259: return(0);
9260: }
9262: /*@
9263: DMGetCompatibility - determine if two DMs are compatible
9265: Collective
9267: Input Parameters:
9268: + dm1 - the first DM
9269: - dm2 - the second DM
9271: Output Parameters:
9272: + compatible - whether or not the two DMs are compatible
9273: - set - whether or not the compatible value was set
9275: Notes:
9276: Two DMs are deemed compatible if they represent the same parallel decomposition
9277: of the same topology. This implies that the section (field data) on one
9278: "makes sense" with respect to the topology and parallel decomposition of the other.
9279: Loosely speaking, compatible DMs represent the same domain and parallel
9280: decomposition, but hold different data.
9282: Typically, one would confirm compatibility if intending to simultaneously iterate
9283: over a pair of vectors obtained from different DMs.
9285: For example, two DMDA objects are compatible if they have the same local
9286: and global sizes and the same stencil width. They can have different numbers
9287: of degrees of freedom per node. Thus, one could use the node numbering from
9288: either DM in bounds for a loop over vectors derived from either DM.
9290: Consider the operation of summing data living on a 2-dof DMDA to data living
9291: on a 1-dof DMDA, which should be compatible, as in the following snippet.
9292: .vb
9293: ...
9294: DMGetCompatibility(da1,da2,&compatible,&set);
9295: if (set && compatible) {
9296: DMDAVecGetArrayDOF(da1,vec1,&arr1);
9297: DMDAVecGetArrayDOF(da2,vec2,&arr2);
9298: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9299: for (j=y; j<y+n; ++j) {
9300: for (i=x; i<x+m, ++i) {
9301: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9302: }
9303: }
9304: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9305: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9306: } else {
9307: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9308: }
9309: ...
9310: .ve
9312: Checking compatibility might be expensive for a given implementation of DM,
9313: or might be impossible to unambiguously confirm or deny. For this reason,
9314: this function may decline to determine compatibility, and hence users should
9315: always check the "set" output parameter.
9317: A DM is always compatible with itself.
9319: In the current implementation, DMs which live on "unequal" communicators
9320: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9321: incompatible.
9323: This function is labeled "Collective," as information about all subdomains
9324: is required on each rank. However, in DM implementations which store all this
9325: information locally, this function may be merely "Logically Collective".
9327: Developer Notes:
9328: Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9329: iff B is compatible with A. Thus, this function checks the implementations
9330: of both dm and dmc (if they are of different types), attempting to determine
9331: compatibility. It is left to DM implementers to ensure that symmetry is
9332: preserved. The simplest way to do this is, when implementing type-specific
9333: logic for this function, is to check for existing logic in the implementation
9334: of other DM types and let *set = PETSC_FALSE if found.
9336: Level: advanced
9338: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9339: @*/
9341: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9342: {
9344: PetscMPIInt compareResult;
9345: DMType type,type2;
9346: PetscBool sameType;
9352: /* Declare a DM compatible with itself */
9353: if (dm1 == dm2) {
9354: *set = PETSC_TRUE;
9355: *compatible = PETSC_TRUE;
9356: return(0);
9357: }
9359: /* Declare a DM incompatible with a DM that lives on an "unequal"
9360: communicator. Note that this does not preclude compatibility with
9361: DMs living on "congruent" or "similar" communicators, but this must be
9362: determined by the implementation-specific logic */
9363: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9364: if (compareResult == MPI_UNEQUAL) {
9365: *set = PETSC_TRUE;
9366: *compatible = PETSC_FALSE;
9367: return(0);
9368: }
9370: /* Pass to the implementation-specific routine, if one exists. */
9371: if (dm1->ops->getcompatibility) {
9372: (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9373: if (*set) return(0);
9374: }
9376: /* If dm1 and dm2 are of different types, then attempt to check compatibility
9377: with an implementation of this function from dm2 */
9378: DMGetType(dm1,&type);
9379: DMGetType(dm2,&type2);
9380: PetscStrcmp(type,type2,&sameType);
9381: if (!sameType && dm2->ops->getcompatibility) {
9382: (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9383: } else {
9384: *set = PETSC_FALSE;
9385: }
9386: return(0);
9387: }
9389: /*@C
9390: DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9392: Logically Collective on DM
9394: Input Parameters:
9395: + DM - the DM
9396: . f - the monitor function
9397: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9398: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9400: Options Database Keys:
9401: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9402: does not cancel those set via the options database.
9404: Notes:
9405: Several different monitoring routines may be set by calling
9406: DMMonitorSet() multiple times; all will be called in the
9407: order in which they were set.
9409: Fortran Notes:
9410: Only a single monitor function can be set for each DM object
9412: Level: intermediate
9414: .seealso: DMMonitorCancel()
9415: @*/
9416: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9417: {
9418: PetscInt m;
9423: for (m = 0; m < dm->numbermonitors; ++m) {
9424: PetscBool identical;
9426: PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9427: if (identical) return(0);
9428: }
9429: if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9430: dm->monitor[dm->numbermonitors] = f;
9431: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
9432: dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9433: return(0);
9434: }
9436: /*@
9437: DMMonitorCancel - Clears all the monitor functions for a DM object.
9439: Logically Collective on DM
9441: Input Parameter:
9442: . dm - the DM
9444: Options Database Key:
9445: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9446: into a code by calls to DMonitorSet(), but does not cancel those
9447: set via the options database
9449: Notes:
9450: There is no way to clear one specific monitor from a DM object.
9452: Level: intermediate
9454: .seealso: DMMonitorSet()
9455: @*/
9456: PetscErrorCode DMMonitorCancel(DM dm)
9457: {
9459: PetscInt m;
9463: for (m = 0; m < dm->numbermonitors; ++m) {
9464: if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9465: }
9466: dm->numbermonitors = 0;
9467: return(0);
9468: }
9470: /*@C
9471: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9473: Collective on DM
9475: Input Parameters:
9476: + dm - DM object you wish to monitor
9477: . name - the monitor type one is seeking
9478: . help - message indicating what monitoring is done
9479: . manual - manual page for the monitor
9480: . monitor - the monitor function
9481: - 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
9483: Output Parameter:
9484: . flg - Flag set if the monitor was created
9486: Level: developer
9488: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9489: PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9490: PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9491: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9492: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9493: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9494: PetscOptionsFList(), PetscOptionsEList()
9495: @*/
9496: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9497: {
9498: PetscViewer viewer;
9499: PetscViewerFormat format;
9500: PetscErrorCode ierr;
9504: PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9505: if (*flg) {
9506: PetscViewerAndFormat *vf;
9508: PetscViewerAndFormatCreate(viewer, format, &vf);
9509: PetscObjectDereference((PetscObject) viewer);
9510: if (monitorsetup) {(*monitorsetup)(dm, vf);}
9511: DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9512: }
9513: return(0);
9514: }
9516: /*@
9517: DMMonitor - runs the user provided monitor routines, if they exist
9519: Collective on DM
9521: Input Parameters:
9522: . dm - The DM
9524: Level: developer
9526: .seealso: DMMonitorSet()
9527: @*/
9528: PetscErrorCode DMMonitor(DM dm)
9529: {
9530: PetscInt m;
9534: if (!dm) return(0);
9536: for (m = 0; m < dm->numbermonitors; ++m) {
9537: (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9538: }
9539: return(0);
9540: }
9542: /*@
9543: DMComputeError - Computes the error assuming the user has given exact solution functions
9545: Collective on DM
9547: Input Parameters:
9548: + dm - The DM
9549: - sol - The solution vector
9551: Input/Output Parameter:
9552: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9553: contains the error in each field
9555: Output Parameter:
9556: . errorVec - A vector to hold the cellwise error (may be NULL)
9558: Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9560: Level: developer
9562: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9563: @*/
9564: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9565: {
9566: PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9567: void **ctxs;
9568: PetscReal time;
9569: PetscInt Nf, f, Nds, s;
9570: PetscErrorCode ierr;
9573: DMGetNumFields(dm, &Nf);
9574: PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9575: DMGetNumDS(dm, &Nds);
9576: for (s = 0; s < Nds; ++s) {
9577: PetscDS ds;
9578: DMLabel label;
9579: IS fieldIS;
9580: const PetscInt *fields;
9581: PetscInt dsNf;
9583: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9584: PetscDSGetNumFields(ds, &dsNf);
9585: if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9586: for (f = 0; f < dsNf; ++f) {
9587: const PetscInt field = fields[f];
9588: PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9589: }
9590: if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9591: }
9592: for (f = 0; f < Nf; ++f) {
9593: if (!exactSol[f]) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %D", f);
9594: }
9595: DMGetOutputSequenceNumber(dm, NULL, &time);
9596: if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9597: if (errorVec) {
9598: DM edm;
9599: DMPolytopeType ct;
9600: PetscBool simplex;
9601: PetscInt dim, cStart, Nf;
9603: DMClone(dm, &edm);
9604: DMGetDimension(edm, &dim);
9605: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9606: DMPlexGetCellType(dm, cStart, &ct);
9607: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9608: DMGetNumFields(dm, &Nf);
9609: for (f = 0; f < Nf; ++f) {
9610: PetscFE fe, efe;
9611: PetscQuadrature q;
9612: const char *name;
9614: DMGetField(dm, f, NULL, (PetscObject *) &fe);
9615: PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9616: PetscObjectGetName((PetscObject) fe, &name);
9617: PetscObjectSetName((PetscObject) efe, name);
9618: PetscFEGetQuadrature(fe, &q);
9619: PetscFESetQuadrature(efe, q);
9620: DMSetField(edm, f, NULL, (PetscObject) efe);
9621: PetscFEDestroy(&efe);
9622: }
9623: DMCreateDS(edm);
9625: DMCreateGlobalVector(edm, errorVec);
9626: PetscObjectSetName((PetscObject) *errorVec, "Error");
9627: DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9628: DMDestroy(&edm);
9629: }
9630: PetscFree2(exactSol, ctxs);
9631: return(0);
9632: }
9634: /*@
9635: DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM
9637: Not collective
9639: Input Parameter:
9640: . dm - The DM
9642: Output Parameter:
9643: . numAux - The number of auxiliary data vectors
9645: Level: advanced
9647: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9648: @*/
9649: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9650: {
9655: PetscHMapAuxGetSize(dm->auxData, numAux);
9656: return(0);
9657: }
9659: /*@
9660: DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value
9662: Not collective
9664: Input Parameters:
9665: + dm - The DM
9666: . label - The DMLabel
9667: - value - The label value indicating the region
9669: Output Parameter:
9670: . aux - The Vec holding auxiliary field data
9672: Note: If no auxiliary vector is found for this (label, value), (NULL, 0) is checked as well.
9674: Level: advanced
9676: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9677: @*/
9678: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec *aux)
9679: {
9680: PetscHashAuxKey key, wild = {NULL, 0};
9681: PetscBool has;
9682: PetscErrorCode ierr;
9687: key.label = label;
9688: key.value = value;
9689: PetscHMapAuxHas(dm->auxData, key, &has);
9690: if (has) {PetscHMapAuxGet(dm->auxData, key, aux);}
9691: else {PetscHMapAuxGet(dm->auxData, wild, aux);}
9692: return(0);
9693: }
9695: /*@
9696: DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value
9698: Not collective
9700: Input Parameters:
9701: + dm - The DM
9702: . label - The DMLabel
9703: . value - The label value indicating the region
9704: - aux - The Vec holding auxiliary field data
9706: Level: advanced
9708: .seealso: DMGetAuxiliaryVec()
9709: @*/
9710: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec aux)
9711: {
9712: Vec old;
9713: PetscHashAuxKey key;
9714: PetscErrorCode ierr;
9719: key.label = label;
9720: key.value = value;
9721: PetscHMapAuxGet(dm->auxData, key, &old);
9722: PetscObjectReference((PetscObject) aux);
9723: PetscObjectDereference((PetscObject) old);
9724: if (!aux) {PetscHMapAuxDel(dm->auxData, key);}
9725: else {PetscHMapAuxSet(dm->auxData, key, aux);}
9726: return(0);
9727: }
9729: /*@C
9730: DMGetAuxiliaryLabels - Get the labels and values for all auxiliary vectors in this DM
9732: Not collective
9734: Input Parameter:
9735: . dm - The DM
9737: Output Parameters:
9738: + labels - The DMLabels for each Vec
9739: - values - The label values for each Vec
9741: Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().
9743: Level: advanced
9745: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9746: @*/
9747: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[])
9748: {
9749: PetscHashAuxKey *keys;
9750: PetscInt n, i, off = 0;
9751: PetscErrorCode ierr;
9757: DMGetNumAuxiliaryVec(dm, &n);
9758: PetscMalloc1(n, &keys);
9759: PetscHMapAuxGetKeys(dm->auxData, &off, keys);
9760: for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value;}
9761: PetscFree(keys);
9762: return(0);
9763: }
9765: /*@
9766: DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM
9768: Not collective
9770: Input Parameter:
9771: . dm - The DM
9773: Output Parameter:
9774: . dmNew - The new DM, now with the same auxiliary data
9776: Level: advanced
9778: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9779: @*/
9780: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9781: {
9786: PetscHMapAuxDestroy(&dmNew->auxData);
9787: PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
9788: return(0);
9789: }
9791: /*@C
9792: DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9794: Not collective
9796: Input Parameters:
9797: + ct - The DMPolytopeType
9798: . sourceCone - The source arrangement of faces
9799: - targetCone - The target arrangement of faces
9801: Output Parameters:
9802: + ornt - The orientation which will take the source arrangement to the target arrangement
9803: - found - Flag indicating that a suitable orientation was found
9805: Level: advanced
9807: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
9808: @*/
9809: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9810: {
9811: const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9812: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9813: PetscInt o, c;
9816: if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9817: for (o = -nO; o < nO; ++o) {
9818: const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9820: for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9821: if (c == cS) {*ornt = o; break;}
9822: }
9823: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9824: return(0);
9825: }
9827: /*@C
9828: DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9830: Not collective
9832: Input Parameters:
9833: + ct - The DMPolytopeType
9834: . sourceCone - The source arrangement of faces
9835: - targetCone - The target arrangement of faces
9837: Output Parameters:
9838: . ornt - The orientation which will take the source arrangement to the target arrangement
9840: Note: This function will fail if no suitable orientation can be found.
9842: Level: advanced
9844: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
9845: @*/
9846: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9847: {
9848: PetscBool found;
9852: DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
9853: if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9854: return(0);
9855: }
9857: /*@C
9858: DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9860: Not collective
9862: Input Parameters:
9863: + ct - The DMPolytopeType
9864: . sourceVert - The source arrangement of vertices
9865: - targetVert - The target arrangement of vertices
9867: Output Parameters:
9868: + ornt - The orientation which will take the source arrangement to the target arrangement
9869: - found - Flag indicating that a suitable orientation was found
9871: Level: advanced
9873: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
9874: @*/
9875: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9876: {
9877: const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9878: const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9879: PetscInt o, c;
9882: if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9883: for (o = -nO; o < nO; ++o) {
9884: const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9886: for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9887: if (c == cS) {*ornt = o; break;}
9888: }
9889: *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9890: return(0);
9891: }
9893: /*@C
9894: DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9896: Not collective
9898: Input Parameters:
9899: + ct - The DMPolytopeType
9900: . sourceCone - The source arrangement of vertices
9901: - targetCone - The target arrangement of vertices
9903: Output Parameters:
9904: . ornt - The orientation which will take the source arrangement to the target arrangement
9906: Note: This function will fail if no suitable orientation can be found.
9908: Level: advanced
9910: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
9911: @*/
9912: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9913: {
9914: PetscBool found;
9918: DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
9919: if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9920: return(0);
9921: }
9923: /*@C
9924: DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9926: Not collective
9928: Input Parameters:
9929: + ct - The DMPolytopeType
9930: - point - Coordinates of the point
9932: Output Parameters:
9933: . inside - Flag indicating whether the point is inside the reference cell of given type
9935: Level: advanced
9937: .seealso: DMLocatePoints()
9938: @*/
9939: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9940: {
9941: PetscReal sum = 0.0;
9942: PetscInt d;
9945: *inside = PETSC_TRUE;
9946: switch (ct) {
9947: case DM_POLYTOPE_TRIANGLE:
9948: case DM_POLYTOPE_TETRAHEDRON:
9949: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9950: if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
9951: sum += point[d];
9952: }
9953: if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9954: break;
9955: case DM_POLYTOPE_QUADRILATERAL:
9956: case DM_POLYTOPE_HEXAHEDRON:
9957: for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9958: if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9959: break;
9960: default:
9961: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9962: }
9963: return(0);
9964: }