Actual source code: dm.c
petsc-3.14.0 2020-09-29
1: #include <petsc/private/dmimpl.h>
2: #include <petsc/private/dmlabelimpl.h>
3: #include <petsc/private/petscdsimpl.h>
4: #include <petscdmplex.h>
5: #include <petscdmfield.h>
6: #include <petscsf.h>
7: #include <petscds.h>
9: #if defined(PETSC_HAVE_VALGRIND)
10: # include <valgrind/memcheck.h>
11: #endif
13: PetscClassId DM_CLASSID;
14: PetscClassId DMLABEL_CLASSID;
15: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load, DM_AdaptInterpolator;
17: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
18: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
19: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
20: /*@
21: DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
23: If you never call DMSetType() it will generate an
24: error when you try to use the vector.
26: Collective
28: Input Parameter:
29: . comm - The communicator for the DM object
31: Output Parameter:
32: . dm - The DM object
34: Level: beginner
36: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
37: @*/
38: PetscErrorCode DMCreate(MPI_Comm comm,DM *dm)
39: {
40: DM v;
41: PetscDS ds;
46: *dm = NULL;
47: DMInitializePackage();
49: PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);
51: v->setupcalled = PETSC_FALSE;
52: v->setfromoptionscalled = PETSC_FALSE;
53: v->ltogmap = NULL;
54: v->bs = 1;
55: v->coloringtype = IS_COLORING_GLOBAL;
56: PetscSFCreate(comm, &v->sf);
57: PetscSFCreate(comm, &v->sectionSF);
58: v->labels = NULL;
59: v->adjacency[0] = PETSC_FALSE;
60: v->adjacency[1] = PETSC_TRUE;
61: v->depthLabel = NULL;
62: v->celltypeLabel = NULL;
63: v->localSection = NULL;
64: v->globalSection = NULL;
65: v->defaultConstraintSection = NULL;
66: v->defaultConstraintMat = NULL;
67: v->L = NULL;
68: v->maxCell = NULL;
69: v->bdtype = NULL;
70: v->dimEmbed = PETSC_DEFAULT;
71: v->dim = PETSC_DETERMINE;
72: {
73: PetscInt i;
74: for (i = 0; i < 10; ++i) {
75: v->nullspaceConstructors[i] = NULL;
76: v->nearnullspaceConstructors[i] = NULL;
77: }
78: }
79: PetscDSCreate(PetscObjectComm((PetscObject) v), &ds);
80: DMSetRegionDS(v, NULL, NULL, ds);
81: PetscDSDestroy(&ds);
82: v->dmBC = NULL;
83: v->coarseMesh = NULL;
84: v->outputSequenceNum = -1;
85: v->outputSequenceVal = 0.0;
86: DMSetVecType(v,VECSTANDARD);
87: DMSetMatType(v,MATAIJ);
89: *dm = v;
90: return(0);
91: }
93: /*@
94: DMClone - Creates a DM object with the same topology as the original.
96: Collective
98: Input Parameter:
99: . dm - The original DM object
101: Output Parameter:
102: . newdm - The new DM object
104: Level: beginner
106: Notes:
107: For some DM implementations this is a shallow clone, the result of which may share (referent counted) information with its parent. For example,
108: DMClone() applied to a DMPLEX object will result in a new DMPLEX that shares the topology with the original DMPLEX. It does not
109: share the PetscSection of the original DM.
111: The clone is considered set up iff the original is.
113: .seealso: DMDestroy(), DMCreate(), DMSetType(), DMSetLocalSection(), DMSetGlobalSection()
115: @*/
116: PetscErrorCode DMClone(DM dm, DM *newdm)
117: {
118: PetscSF sf;
119: Vec coords;
120: void *ctx;
121: PetscInt dim, cdim;
127: DMCreate(PetscObjectComm((PetscObject) dm), newdm);
128: DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
129: (*newdm)->leveldown = dm->leveldown;
130: (*newdm)->levelup = dm->levelup;
131: DMGetDimension(dm, &dim);
132: DMSetDimension(*newdm, dim);
133: if (dm->ops->clone) {
134: (*dm->ops->clone)(dm, newdm);
135: }
136: (*newdm)->setupcalled = dm->setupcalled;
137: DMGetPointSF(dm, &sf);
138: DMSetPointSF(*newdm, sf);
139: DMGetApplicationContext(dm, &ctx);
140: DMSetApplicationContext(*newdm, ctx);
141: if (dm->coordinateDM) {
142: DM ncdm;
143: PetscSection cs;
144: PetscInt pEnd = -1, pEndMax = -1;
146: DMGetLocalSection(dm->coordinateDM, &cs);
147: if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
148: MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
149: if (pEndMax >= 0) {
150: DMClone(dm->coordinateDM, &ncdm);
151: DMCopyDisc(dm->coordinateDM, ncdm);
152: DMSetLocalSection(ncdm, cs);
153: DMSetCoordinateDM(*newdm, ncdm);
154: DMDestroy(&ncdm);
155: }
156: }
157: DMGetCoordinateDim(dm, &cdim);
158: DMSetCoordinateDim(*newdm, cdim);
159: DMGetCoordinatesLocal(dm, &coords);
160: if (coords) {
161: DMSetCoordinatesLocal(*newdm, coords);
162: } else {
163: DMGetCoordinates(dm, &coords);
164: if (coords) {DMSetCoordinates(*newdm, coords);}
165: }
166: {
167: PetscBool isper;
168: const PetscReal *maxCell, *L;
169: const DMBoundaryType *bd;
170: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
171: DMSetPeriodicity(*newdm, isper, maxCell, L, bd);
172: }
173: {
174: PetscBool useCone, useClosure;
176: DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
177: DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
178: }
179: return(0);
180: }
182: /*@C
183: DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
185: Logically Collective on da
187: Input Parameter:
188: + da - initial distributed array
189: . ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL
191: Options Database:
192: . -dm_vec_type ctype
194: Level: intermediate
196: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
197: @*/
198: PetscErrorCode DMSetVecType(DM da,VecType ctype)
199: {
204: PetscFree(da->vectype);
205: PetscStrallocpy(ctype,(char**)&da->vectype);
206: return(0);
207: }
209: /*@C
210: DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
212: Logically Collective on da
214: Input Parameter:
215: . da - initial distributed array
217: Output Parameter:
218: . ctype - the vector type
220: Level: intermediate
222: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
223: @*/
224: PetscErrorCode DMGetVecType(DM da,VecType *ctype)
225: {
228: *ctype = da->vectype;
229: return(0);
230: }
232: /*@
233: VecGetDM - Gets the DM defining the data layout of the vector
235: Not collective
237: Input Parameter:
238: . v - The Vec
240: Output Parameter:
241: . dm - The DM
243: Level: intermediate
245: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
246: @*/
247: PetscErrorCode VecGetDM(Vec v, DM *dm)
248: {
254: PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
255: return(0);
256: }
258: /*@
259: VecSetDM - Sets the DM defining the data layout of the vector.
261: Not collective
263: Input Parameters:
264: + v - The Vec
265: - dm - The DM
267: Note: This is NOT the same as DMCreateGlobalVector() since it does not change the view methods or perform other customization, but merely sets the DM member.
269: Level: intermediate
271: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
272: @*/
273: PetscErrorCode VecSetDM(Vec v, DM dm)
274: {
280: PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
281: return(0);
282: }
284: /*@C
285: DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM
287: Logically Collective on dm
289: Input Parameters:
290: + dm - the DM context
291: - ctype - the matrix type
293: Options Database:
294: . -dm_is_coloring_type - global or local
296: Level: intermediate
298: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
299: DMGetISColoringType()
300: @*/
301: PetscErrorCode DMSetISColoringType(DM dm,ISColoringType ctype)
302: {
305: dm->coloringtype = ctype;
306: return(0);
307: }
309: /*@C
310: DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM
312: Logically Collective on dm
314: Input Parameter:
315: . dm - the DM context
317: Output Parameter:
318: . ctype - the matrix type
320: Options Database:
321: . -dm_is_coloring_type - global or local
323: Level: intermediate
325: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
326: DMGetISColoringType()
327: @*/
328: PetscErrorCode DMGetISColoringType(DM dm,ISColoringType *ctype)
329: {
332: *ctype = dm->coloringtype;
333: return(0);
334: }
336: /*@C
337: DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
339: Logically Collective on dm
341: Input Parameters:
342: + dm - the DM context
343: - ctype - the matrix type
345: Options Database:
346: . -dm_mat_type ctype
348: Level: intermediate
350: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
351: @*/
352: PetscErrorCode DMSetMatType(DM dm,MatType ctype)
353: {
358: PetscFree(dm->mattype);
359: PetscStrallocpy(ctype,(char**)&dm->mattype);
360: return(0);
361: }
363: /*@C
364: DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
366: Logically Collective on dm
368: Input Parameter:
369: . dm - the DM context
371: Output Parameter:
372: . ctype - the matrix type
374: Options Database:
375: . -dm_mat_type ctype
377: Level: intermediate
379: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
380: @*/
381: PetscErrorCode DMGetMatType(DM dm,MatType *ctype)
382: {
385: *ctype = dm->mattype;
386: return(0);
387: }
389: /*@
390: MatGetDM - Gets the DM defining the data layout of the matrix
392: Not collective
394: Input Parameter:
395: . A - The Mat
397: Output Parameter:
398: . dm - The DM
400: Level: intermediate
402: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
403: the Mat through a PetscObjectCompose() operation
405: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
406: @*/
407: PetscErrorCode MatGetDM(Mat A, DM *dm)
408: {
414: PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
415: return(0);
416: }
418: /*@
419: MatSetDM - Sets the DM defining the data layout of the matrix
421: Not collective
423: Input Parameters:
424: + A - The Mat
425: - dm - The DM
427: Level: intermediate
429: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
430: the Mat through a PetscObjectCompose() operation
433: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
434: @*/
435: PetscErrorCode MatSetDM(Mat A, DM dm)
436: {
442: PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
443: return(0);
444: }
446: /*@C
447: DMSetOptionsPrefix - Sets the prefix used for searching for all
448: DM options in the database.
450: Logically Collective on dm
452: Input Parameter:
453: + da - the DM context
454: - prefix - the prefix to prepend to all option names
456: Notes:
457: A hyphen (-) must NOT be given at the beginning of the prefix name.
458: The first character of all runtime options is AUTOMATICALLY the hyphen.
460: Level: advanced
462: .seealso: DMSetFromOptions()
463: @*/
464: PetscErrorCode DMSetOptionsPrefix(DM dm,const char prefix[])
465: {
470: PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
471: if (dm->sf) {
472: PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
473: }
474: if (dm->sectionSF) {
475: PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
476: }
477: return(0);
478: }
480: /*@C
481: DMAppendOptionsPrefix - Appends to the prefix used for searching for all
482: DM options in the database.
484: Logically Collective on dm
486: Input Parameters:
487: + dm - the DM context
488: - prefix - the prefix string to prepend to all DM option requests
490: Notes:
491: A hyphen (-) must NOT be given at the beginning of the prefix name.
492: The first character of all runtime options is AUTOMATICALLY the hyphen.
494: Level: advanced
496: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
497: @*/
498: PetscErrorCode DMAppendOptionsPrefix(DM dm,const char prefix[])
499: {
504: PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
505: return(0);
506: }
508: /*@C
509: DMGetOptionsPrefix - Gets the prefix used for searching for all
510: DM options in the database.
512: Not Collective
514: Input Parameters:
515: . dm - the DM context
517: Output Parameters:
518: . prefix - pointer to the prefix string used is returned
520: Notes:
521: On the fortran side, the user should pass in a string 'prefix' of
522: sufficient length to hold the prefix.
524: Level: advanced
526: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
527: @*/
528: PetscErrorCode DMGetOptionsPrefix(DM dm,const char *prefix[])
529: {
534: PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
535: return(0);
536: }
538: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
539: {
540: PetscInt refct = ((PetscObject) dm)->refct;
544: *ncrefct = 0;
545: if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
546: refct--;
547: if (recurseCoarse) {
548: PetscInt coarseCount;
550: DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
551: refct += coarseCount;
552: }
553: }
554: if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
555: refct--;
556: if (recurseFine) {
557: PetscInt fineCount;
559: DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
560: refct += fineCount;
561: }
562: }
563: *ncrefct = refct;
564: return(0);
565: }
567: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
568: {
569: DMLabelLink next = dm->labels;
573: /* destroy the labels */
574: while (next) {
575: DMLabelLink tmp = next->next;
577: if (next->label == dm->depthLabel) dm->depthLabel = NULL;
578: if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
579: DMLabelDestroy(&next->label);
580: PetscFree(next);
581: next = tmp;
582: }
583: dm->labels = NULL;
584: return(0);
585: }
587: /*@
588: DMDestroy - Destroys a vector packer or DM.
590: Collective on dm
592: Input Parameter:
593: . dm - the DM object to destroy
595: Level: developer
597: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
599: @*/
600: PetscErrorCode DMDestroy(DM *dm)
601: {
602: PetscInt cnt;
603: DMNamedVecLink nlink,nnext;
607: if (!*dm) return(0);
610: /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
611: DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
612: --((PetscObject)(*dm))->refct;
613: if (--cnt > 0) {*dm = NULL; return(0);}
614: if (((PetscObject)(*dm))->refct < 0) return(0);
615: ((PetscObject)(*dm))->refct = 0;
617: DMClearGlobalVectors(*dm);
618: DMClearLocalVectors(*dm);
620: nnext=(*dm)->namedglobal;
621: (*dm)->namedglobal = NULL;
622: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
623: nnext = nlink->next;
624: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
625: PetscFree(nlink->name);
626: VecDestroy(&nlink->X);
627: PetscFree(nlink);
628: }
629: nnext=(*dm)->namedlocal;
630: (*dm)->namedlocal = NULL;
631: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
632: nnext = nlink->next;
633: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
634: PetscFree(nlink->name);
635: VecDestroy(&nlink->X);
636: PetscFree(nlink);
637: }
639: /* Destroy the list of hooks */
640: {
641: DMCoarsenHookLink link,next;
642: for (link=(*dm)->coarsenhook; link; link=next) {
643: next = link->next;
644: PetscFree(link);
645: }
646: (*dm)->coarsenhook = NULL;
647: }
648: {
649: DMRefineHookLink link,next;
650: for (link=(*dm)->refinehook; link; link=next) {
651: next = link->next;
652: PetscFree(link);
653: }
654: (*dm)->refinehook = NULL;
655: }
656: {
657: DMSubDomainHookLink link,next;
658: for (link=(*dm)->subdomainhook; link; link=next) {
659: next = link->next;
660: PetscFree(link);
661: }
662: (*dm)->subdomainhook = NULL;
663: }
664: {
665: DMGlobalToLocalHookLink link,next;
666: for (link=(*dm)->gtolhook; link; link=next) {
667: next = link->next;
668: PetscFree(link);
669: }
670: (*dm)->gtolhook = NULL;
671: }
672: {
673: DMLocalToGlobalHookLink link,next;
674: for (link=(*dm)->ltoghook; link; link=next) {
675: next = link->next;
676: PetscFree(link);
677: }
678: (*dm)->ltoghook = NULL;
679: }
680: /* Destroy the work arrays */
681: {
682: DMWorkLink link,next;
683: if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
684: for (link=(*dm)->workin; link; link=next) {
685: next = link->next;
686: PetscFree(link->mem);
687: PetscFree(link);
688: }
689: (*dm)->workin = NULL;
690: }
691: /* destroy the labels */
692: DMDestroyLabelLinkList_Internal(*dm);
693: /* destroy the fields */
694: DMClearFields(*dm);
695: /* destroy the boundaries */
696: {
697: DMBoundary next = (*dm)->boundary;
698: while (next) {
699: DMBoundary b = next;
701: next = b->next;
702: PetscFree(b);
703: }
704: }
706: PetscObjectDestroy(&(*dm)->dmksp);
707: PetscObjectDestroy(&(*dm)->dmsnes);
708: PetscObjectDestroy(&(*dm)->dmts);
710: if ((*dm)->ctx && (*dm)->ctxdestroy) {
711: (*(*dm)->ctxdestroy)(&(*dm)->ctx);
712: }
713: MatFDColoringDestroy(&(*dm)->fd);
714: ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
715: PetscFree((*dm)->vectype);
716: PetscFree((*dm)->mattype);
718: PetscSectionDestroy(&(*dm)->localSection);
719: PetscSectionDestroy(&(*dm)->globalSection);
720: PetscLayoutDestroy(&(*dm)->map);
721: PetscSectionDestroy(&(*dm)->defaultConstraintSection);
722: MatDestroy(&(*dm)->defaultConstraintMat);
723: PetscSFDestroy(&(*dm)->sf);
724: PetscSFDestroy(&(*dm)->sectionSF);
725: if ((*dm)->useNatural) {
726: if ((*dm)->sfNatural) {
727: PetscSFDestroy(&(*dm)->sfNatural);
728: }
729: PetscObjectDereference((PetscObject) (*dm)->sfMigration);
730: }
731: if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
732: DMSetFineDM((*dm)->coarseMesh,NULL);
733: }
735: DMDestroy(&(*dm)->coarseMesh);
736: if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
737: DMSetCoarseDM((*dm)->fineMesh,NULL);
738: }
739: DMDestroy(&(*dm)->fineMesh);
740: DMFieldDestroy(&(*dm)->coordinateField);
741: DMDestroy(&(*dm)->coordinateDM);
742: VecDestroy(&(*dm)->coordinates);
743: VecDestroy(&(*dm)->coordinatesLocal);
744: PetscFree((*dm)->L);
745: PetscFree((*dm)->maxCell);
746: PetscFree((*dm)->bdtype);
747: if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
748: DMDestroy(&(*dm)->transformDM);
749: VecDestroy(&(*dm)->transform);
751: DMClearDS(*dm);
752: DMDestroy(&(*dm)->dmBC);
753: /* if memory was published with SAWs then destroy it */
754: PetscObjectSAWsViewOff((PetscObject)*dm);
756: if ((*dm)->ops->destroy) {
757: (*(*dm)->ops->destroy)(*dm);
758: }
759: DMMonitorCancel(*dm);
760: /* We do not destroy (*dm)->data here so that we can reference count backend objects */
761: PetscHeaderDestroy(dm);
762: return(0);
763: }
765: /*@
766: DMSetUp - sets up the data structures inside a DM object
768: Collective on dm
770: Input Parameter:
771: . dm - the DM object to setup
773: Level: developer
775: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
777: @*/
778: PetscErrorCode DMSetUp(DM dm)
779: {
784: if (dm->setupcalled) return(0);
785: if (dm->ops->setup) {
786: (*dm->ops->setup)(dm);
787: }
788: dm->setupcalled = PETSC_TRUE;
789: return(0);
790: }
792: /*@
793: DMSetFromOptions - sets parameters in a DM from the options database
795: Collective on dm
797: Input Parameter:
798: . dm - the DM object to set options for
800: Options Database:
801: + -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
802: . -dm_vec_type <type> - type of vector to create inside DM
803: . -dm_mat_type <type> - type of matrix to create inside DM
804: - -dm_is_coloring_type - <global or local>
806: DMPLEX Specific Checks
807: + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
808: . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
809: . -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()
810: . -dm_plex_check_geometry - Check that cells have positive volume - DMPlexCheckGeometry()
811: . -dm_plex_check_pointsf - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
812: . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
813: - -dm_plex_check_all - Perform all the checks above
815: Level: intermediate
817: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(),
818: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces(), DMPlexCheckGeometry(), DMPlexCheckPointSF(), DMPlexCheckInterfaceCones()
820: @*/
821: PetscErrorCode DMSetFromOptions(DM dm)
822: {
823: char typeName[256];
824: PetscBool flg;
829: dm->setfromoptionscalled = PETSC_TRUE;
830: if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
831: if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
832: PetscObjectOptionsBegin((PetscObject)dm);
833: PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
834: PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
835: if (flg) {
836: DMSetVecType(dm,typeName);
837: }
838: PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
839: if (flg) {
840: DMSetMatType(dm,typeName);
841: }
842: PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
843: if (dm->ops->setfromoptions) {
844: (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
845: }
846: /* process any options handlers added with PetscObjectAddOptionsHandler() */
847: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
848: PetscOptionsEnd();
849: return(0);
850: }
852: /*@C
853: DMViewFromOptions - View from Options
855: Collective on DM
857: Input Parameters:
858: + dm - the DM object
859: . obj - Optional object
860: - name - command line option
862: Level: intermediate
863: .seealso: DM, DMView, PetscObjectViewFromOptions(), DMCreate()
864: @*/
865: PetscErrorCode DMViewFromOptions(DM dm,PetscObject obj,const char name[])
866: {
871: PetscObjectViewFromOptions((PetscObject)dm,obj,name);
872: return(0);
873: }
875: /*@C
876: DMView - Views a DM
878: Collective on dm
880: Input Parameter:
881: + dm - the DM object to view
882: - v - the viewer
884: Level: beginner
886: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
888: @*/
889: PetscErrorCode DMView(DM dm,PetscViewer v)
890: {
891: PetscErrorCode ierr;
892: PetscBool isbinary;
893: PetscMPIInt size;
894: PetscViewerFormat format;
898: if (!v) {
899: PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
900: }
902: /* Ideally, we would like to have this test on.
903: However, it currently breaks socket viz via GLVis.
904: During DMView(parallel_mesh,glvis_viewer), each
905: process opens a sequential ASCII socket to visualize
906: the local mesh, and PetscObjectView(dm,local_socket)
907: is internally called inside VecView_GLVis, incurring
908: in an error here */
910: PetscViewerCheckWritable(v);
912: PetscViewerGetFormat(v,&format);
913: MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
914: if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
915: PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
916: PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
917: if (isbinary) {
918: PetscInt classid = DM_FILE_CLASSID;
919: char type[256];
921: PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
922: PetscStrncpy(type,((PetscObject)dm)->type_name,256);
923: PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
924: }
925: if (dm->ops->view) {
926: (*dm->ops->view)(dm,v);
927: }
928: return(0);
929: }
931: /*@
932: DMCreateGlobalVector - Creates a global vector from a DM object
934: Collective on dm
936: Input Parameter:
937: . dm - the DM object
939: Output Parameter:
940: . vec - the global vector
942: Level: beginner
944: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
946: @*/
947: PetscErrorCode DMCreateGlobalVector(DM dm,Vec *vec)
948: {
954: if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
955: (*dm->ops->createglobalvector)(dm,vec);
956: if (PetscDefined(USE_DEBUG)) {
957: DM vdm;
959: VecGetDM(*vec,&vdm);
960: 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);
961: }
962: return(0);
963: }
965: /*@
966: DMCreateLocalVector - Creates a local vector from a DM object
968: Not Collective
970: Input Parameter:
971: . dm - the DM object
973: Output Parameter:
974: . vec - the local vector
976: Level: beginner
978: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
980: @*/
981: PetscErrorCode DMCreateLocalVector(DM dm,Vec *vec)
982: {
988: if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
989: (*dm->ops->createlocalvector)(dm,vec);
990: if (PetscDefined(USE_DEBUG)) {
991: DM vdm;
993: VecGetDM(*vec,&vdm);
994: 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);
995: }
996: return(0);
997: }
999: /*@
1000: DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
1002: Collective on dm
1004: Input Parameter:
1005: . dm - the DM that provides the mapping
1007: Output Parameter:
1008: . ltog - the mapping
1010: Level: intermediate
1012: Notes:
1013: This mapping can then be used by VecSetLocalToGlobalMapping() or
1014: MatSetLocalToGlobalMapping().
1016: .seealso: DMCreateLocalVector()
1017: @*/
1018: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1019: {
1020: PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1026: if (!dm->ltogmap) {
1027: PetscSection section, sectionGlobal;
1029: DMGetLocalSection(dm, §ion);
1030: if (section) {
1031: const PetscInt *cdofs;
1032: PetscInt *ltog;
1033: PetscInt pStart, pEnd, n, p, k, l;
1035: DMGetGlobalSection(dm, §ionGlobal);
1036: PetscSectionGetChart(section, &pStart, &pEnd);
1037: PetscSectionGetStorageSize(section, &n);
1038: PetscMalloc1(n, <og); /* We want the local+overlap size */
1039: for (p = pStart, l = 0; p < pEnd; ++p) {
1040: PetscInt bdof, cdof, dof, off, c, cind = 0;
1042: /* Should probably use constrained dofs */
1043: PetscSectionGetDof(section, p, &dof);
1044: PetscSectionGetConstraintDof(section, p, &cdof);
1045: PetscSectionGetConstraintIndices(section, p, &cdofs);
1046: PetscSectionGetOffset(sectionGlobal, p, &off);
1047: /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1048: bdof = cdof && (dof-cdof) ? 1 : dof;
1049: if (dof) {
1050: if (bs < 0) {bs = bdof;}
1051: else if (bs != bdof) {bs = 1;}
1052: }
1053: for (c = 0; c < dof; ++c, ++l) {
1054: if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1055: else ltog[l] = (off < 0 ? -(off+1) : off) + c;
1056: }
1057: }
1058: /* Must have same blocksize on all procs (some might have no points) */
1059: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1060: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1061: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1062: else {bs = bsMinMax[0];}
1063: bs = bs < 0 ? 1 : bs;
1064: /* Must reduce indices by blocksize */
1065: if (bs > 1) {
1066: for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1067: n /= bs;
1068: }
1069: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1070: PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1071: } else {
1072: if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1073: (*dm->ops->getlocaltoglobalmapping)(dm);
1074: }
1075: }
1076: *ltog = dm->ltogmap;
1077: return(0);
1078: }
1080: /*@
1081: DMGetBlockSize - Gets the inherent block size associated with a DM
1083: Not Collective
1085: Input Parameter:
1086: . dm - the DM with block structure
1088: Output Parameter:
1089: . bs - the block size, 1 implies no exploitable block structure
1091: Level: intermediate
1093: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1094: @*/
1095: PetscErrorCode DMGetBlockSize(DM dm,PetscInt *bs)
1096: {
1100: if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1101: *bs = dm->bs;
1102: return(0);
1103: }
1105: /*@
1106: DMCreateInterpolation - Gets interpolation matrix between two DM objects
1108: Collective on dmc
1110: Input Parameter:
1111: + dmc - the DM object
1112: - dmf - the second, finer DM object
1114: Output Parameter:
1115: + mat - the interpolation
1116: - vec - the scaling (optional)
1118: Level: developer
1120: Notes:
1121: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1122: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1124: For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1125: EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1128: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolationScale()
1130: @*/
1131: PetscErrorCode DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1132: {
1139: if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1140: PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1141: (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1142: PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1143: return(0);
1144: }
1146: /*@
1147: DMCreateInterpolationScale - Forms L = 1/(R*1) such that diag(L)*R preserves scale and is thus suitable for state (versus residual) restriction.
1149: Input Parameters:
1150: + dac - DM that defines a coarse mesh
1151: . daf - DM that defines a fine mesh
1152: - mat - the restriction (or interpolation operator) from fine to coarse
1154: Output Parameter:
1155: . scale - the scaled vector
1157: Level: developer
1159: .seealso: DMCreateInterpolation()
1161: @*/
1162: PetscErrorCode DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1163: {
1165: Vec fine;
1166: PetscScalar one = 1.0;
1169: DMCreateGlobalVector(daf,&fine);
1170: DMCreateGlobalVector(dac,scale);
1171: VecSet(fine,one);
1172: MatRestrict(mat,fine,*scale);
1173: VecDestroy(&fine);
1174: VecReciprocal(*scale);
1175: return(0);
1176: }
1178: /*@
1179: DMCreateRestriction - Gets restriction matrix between two DM objects
1181: Collective on dmc
1183: Input Parameter:
1184: + dmc - the DM object
1185: - dmf - the second, finer DM object
1187: Output Parameter:
1188: . mat - the restriction
1191: Level: developer
1193: Notes:
1194: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1195: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1198: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()
1200: @*/
1201: PetscErrorCode DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1202: {
1209: if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1210: PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1211: (*dmc->ops->createrestriction)(dmc,dmf,mat);
1212: PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1213: return(0);
1214: }
1216: /*@
1217: DMCreateInjection - Gets injection matrix between two DM objects
1219: Collective on dac
1221: Input Parameter:
1222: + dac - the DM object
1223: - daf - the second, finer DM object
1225: Output Parameter:
1226: . mat - the injection
1228: Level: developer
1230: Notes:
1231: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1232: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
1234: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
1236: @*/
1237: PetscErrorCode DMCreateInjection(DM dac,DM daf,Mat *mat)
1238: {
1245: if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1246: PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1247: (*dac->ops->createinjection)(dac,daf,mat);
1248: PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1249: return(0);
1250: }
1252: /*@
1253: DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j
1255: Collective on dac
1257: Input Parameter:
1258: + dac - the DM object
1259: - daf - the second, finer DM object
1261: Output Parameter:
1262: . mat - the interpolation
1264: Level: developer
1266: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1267: @*/
1268: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1269: {
1276: if (!dac->ops->createmassmatrix) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMassMatrix",((PetscObject)dac)->type_name);
1277: (*dac->ops->createmassmatrix)(dac, daf, mat);
1278: return(0);
1279: }
1281: /*@
1282: DMCreateColoring - Gets coloring for a DM
1284: Collective on dm
1286: Input Parameter:
1287: + dm - the DM object
1288: - ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL
1290: Output Parameter:
1291: . coloring - the coloring
1293: Notes:
1294: Coloring of matrices can be computed directly from the sparse matrix nonzero structure via the MatColoring object or from the mesh from which the
1295: matrix comes from. In general using the mesh produces a more optimal coloring (fewer colors).
1297: This produces a coloring with the distance of 2, see MatSetColoringDistance() which can be used for efficiently computing Jacobians with MatFDColoringCreate()
1299: Level: developer
1301: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType(), MatColoring, MatFDColoringCreate()
1303: @*/
1304: PetscErrorCode DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1305: {
1311: if (!dm->ops->getcoloring) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateColoring",((PetscObject)dm)->type_name);
1312: (*dm->ops->getcoloring)(dm,ctype,coloring);
1313: return(0);
1314: }
1316: /*@
1317: DMCreateMatrix - Gets empty Jacobian for a DM
1319: Collective on dm
1321: Input Parameter:
1322: . dm - the DM object
1324: Output Parameter:
1325: . mat - the empty Jacobian
1327: Level: beginner
1329: Notes:
1330: This properly preallocates the number of nonzeros in the sparse matrix so you
1331: do not need to do it yourself.
1333: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1334: the nonzero pattern call DMSetMatrixPreallocateOnly()
1336: For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1337: internally by PETSc.
1339: For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1340: the indices for the global numbering for DMDAs which is complicated.
1342: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1344: @*/
1345: PetscErrorCode DMCreateMatrix(DM dm,Mat *mat)
1346: {
1352: if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1353: MatInitializePackage();
1354: PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1355: (*dm->ops->creatematrix)(dm,mat);
1356: if (PetscDefined(USE_DEBUG)) {
1357: DM mdm;
1359: MatGetDM(*mat,&mdm);
1360: 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);
1361: }
1362: /* Handle nullspace and near nullspace */
1363: if (dm->Nf) {
1364: MatNullSpace nullSpace;
1365: PetscInt Nf;
1367: DMGetNumFields(dm, &Nf);
1368: if (Nf == 1) {
1369: if (dm->nullspaceConstructors[0]) {
1370: (*dm->nullspaceConstructors[0])(dm, 0, 0, &nullSpace);
1371: MatSetNullSpace(*mat, nullSpace);
1372: MatNullSpaceDestroy(&nullSpace);
1373: }
1374: if (dm->nearnullspaceConstructors[0]) {
1375: (*dm->nearnullspaceConstructors[0])(dm, 0, 0, &nullSpace);
1376: MatSetNearNullSpace(*mat, nullSpace);
1377: MatNullSpaceDestroy(&nullSpace);
1378: }
1379: }
1380: }
1381: PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1382: return(0);
1383: }
1385: /*@
1386: DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1387: preallocated but the nonzero structure and zero values will not be set.
1389: Logically Collective on dm
1391: Input Parameter:
1392: + dm - the DM
1393: - only - PETSC_TRUE if only want preallocation
1395: Level: developer
1396: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1397: @*/
1398: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1399: {
1402: dm->prealloc_only = only;
1403: return(0);
1404: }
1406: /*@
1407: DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1408: but the array for values will not be allocated.
1410: Logically Collective on dm
1412: Input Parameter:
1413: + dm - the DM
1414: - only - PETSC_TRUE if only want matrix stucture
1416: Level: developer
1417: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1418: @*/
1419: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1420: {
1423: dm->structure_only = only;
1424: return(0);
1425: }
1427: /*@C
1428: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1430: Not Collective
1432: Input Parameters:
1433: + dm - the DM object
1434: . count - The minium size
1435: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1437: Output Parameter:
1438: . array - the work array
1440: Level: developer
1442: .seealso DMDestroy(), DMCreate()
1443: @*/
1444: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1445: {
1447: DMWorkLink link;
1448: PetscMPIInt dsize;
1453: if (dm->workin) {
1454: link = dm->workin;
1455: dm->workin = dm->workin->next;
1456: } else {
1457: PetscNewLog(dm,&link);
1458: }
1459: MPI_Type_size(dtype,&dsize);
1460: if (((size_t)dsize*count) > link->bytes) {
1461: PetscFree(link->mem);
1462: PetscMalloc(dsize*count,&link->mem);
1463: link->bytes = dsize*count;
1464: }
1465: link->next = dm->workout;
1466: dm->workout = link;
1467: #if defined(PETSC_HAVE_VALGRIND)
1468: VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1469: VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1470: #endif
1471: *(void**)mem = link->mem;
1472: return(0);
1473: }
1475: /*@C
1476: DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1478: Not Collective
1480: Input Parameters:
1481: + dm - the DM object
1482: . count - The minium size
1483: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1485: Output Parameter:
1486: . array - the work array
1488: Level: developer
1490: Developer Notes:
1491: count and dtype are ignored, they are only needed for DMGetWorkArray()
1492: .seealso DMDestroy(), DMCreate()
1493: @*/
1494: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1495: {
1496: DMWorkLink *p,link;
1501: for (p=&dm->workout; (link=*p); p=&link->next) {
1502: if (link->mem == *(void**)mem) {
1503: *p = link->next;
1504: link->next = dm->workin;
1505: dm->workin = link;
1506: *(void**)mem = NULL;
1507: return(0);
1508: }
1509: }
1510: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1511: }
1513: /*@C
1514: DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field
1516: Logically collective on DM
1518: Input Parameters:
1519: + dm - The DM
1520: . field - The field number for the nullspace
1521: - nullsp - A callback to create the nullspace
1523: Notes:
1524: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1525: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1526: $ dm - The present DM
1527: $ origField - The field number given above, in the original DM
1528: $ field - The field number in dm
1529: $ nullSpace - The nullspace for the given field
1531: This function is currently not available from Fortran.
1533: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1534: */
1535: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1536: {
1539: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1540: dm->nullspaceConstructors[field] = nullsp;
1541: return(0);
1542: }
1544: /*@C
1545: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL
1547: Not collective
1549: Input Parameters:
1550: + dm - The DM
1551: - field - The field number for the nullspace
1553: Output Parameter:
1554: . nullsp - A callback to create the nullspace
1556: Notes:
1557: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1558: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1559: $ dm - The present DM
1560: $ origField - The field number given above, in the original DM
1561: $ field - The field number in dm
1562: $ nullSpace - The nullspace for the given field
1564: This function is currently not available from Fortran.
1566: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1567: */
1568: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1569: {
1573: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1574: *nullsp = dm->nullspaceConstructors[field];
1575: return(0);
1576: }
1578: /*@C
1579: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field
1581: Logically collective on DM
1583: Input Parameters:
1584: + dm - The DM
1585: . field - The field number for the nullspace
1586: - nullsp - A callback to create the near-nullspace
1588: Notes:
1589: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1590: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1591: $ dm - The present DM
1592: $ origField - The field number given above, in the original DM
1593: $ field - The field number in dm
1594: $ nullSpace - The nullspace for the given field
1596: This function is currently not available from Fortran.
1598: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1599: */
1600: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1601: {
1604: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1605: dm->nearnullspaceConstructors[field] = nullsp;
1606: return(0);
1607: }
1609: /*@C
1610: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL
1612: Not collective
1614: Input Parameters:
1615: + dm - The DM
1616: - field - The field number for the nullspace
1618: Output Parameter:
1619: . nullsp - A callback to create the near-nullspace
1621: Notes:
1622: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1623: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1624: $ dm - The present DM
1625: $ origField - The field number given above, in the original DM
1626: $ field - The field number in dm
1627: $ nullSpace - The nullspace for the given field
1629: This function is currently not available from Fortran.
1631: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1632: */
1633: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1634: {
1638: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1639: *nullsp = dm->nearnullspaceConstructors[field];
1640: return(0);
1641: }
1643: /*@C
1644: DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1646: Not collective
1648: Input Parameter:
1649: . dm - the DM object
1651: Output Parameters:
1652: + numFields - The number of fields (or NULL if not requested)
1653: . fieldNames - The name for each field (or NULL if not requested)
1654: - fields - The global indices for each field (or NULL if not requested)
1656: Level: intermediate
1658: Notes:
1659: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1660: PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1661: PetscFree().
1663: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1664: @*/
1665: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1666: {
1667: PetscSection section, sectionGlobal;
1672: if (numFields) {
1674: *numFields = 0;
1675: }
1676: if (fieldNames) {
1678: *fieldNames = NULL;
1679: }
1680: if (fields) {
1682: *fields = NULL;
1683: }
1684: DMGetLocalSection(dm, §ion);
1685: if (section) {
1686: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1687: PetscInt nF, f, pStart, pEnd, p;
1689: DMGetGlobalSection(dm, §ionGlobal);
1690: PetscSectionGetNumFields(section, &nF);
1691: PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1692: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1693: for (f = 0; f < nF; ++f) {
1694: fieldSizes[f] = 0;
1695: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1696: }
1697: for (p = pStart; p < pEnd; ++p) {
1698: PetscInt gdof;
1700: PetscSectionGetDof(sectionGlobal, p, &gdof);
1701: if (gdof > 0) {
1702: for (f = 0; f < nF; ++f) {
1703: PetscInt fdof, fcdof, fpdof;
1705: PetscSectionGetFieldDof(section, p, f, &fdof);
1706: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1707: fpdof = fdof-fcdof;
1708: if (fpdof && fpdof != fieldNc[f]) {
1709: /* Layout does not admit a pointwise block size */
1710: fieldNc[f] = 1;
1711: }
1712: fieldSizes[f] += fpdof;
1713: }
1714: }
1715: }
1716: for (f = 0; f < nF; ++f) {
1717: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1718: fieldSizes[f] = 0;
1719: }
1720: for (p = pStart; p < pEnd; ++p) {
1721: PetscInt gdof, goff;
1723: PetscSectionGetDof(sectionGlobal, p, &gdof);
1724: if (gdof > 0) {
1725: PetscSectionGetOffset(sectionGlobal, p, &goff);
1726: for (f = 0; f < nF; ++f) {
1727: PetscInt fdof, fcdof, fc;
1729: PetscSectionGetFieldDof(section, p, f, &fdof);
1730: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1731: for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1732: fieldIndices[f][fieldSizes[f]] = goff++;
1733: }
1734: }
1735: }
1736: }
1737: if (numFields) *numFields = nF;
1738: if (fieldNames) {
1739: PetscMalloc1(nF, fieldNames);
1740: for (f = 0; f < nF; ++f) {
1741: const char *fieldName;
1743: PetscSectionGetFieldName(section, f, &fieldName);
1744: PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1745: }
1746: }
1747: if (fields) {
1748: PetscMalloc1(nF, fields);
1749: for (f = 0; f < nF; ++f) {
1750: PetscInt bs, in[2], out[2];
1752: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1753: in[0] = -fieldNc[f];
1754: in[1] = fieldNc[f];
1755: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1756: bs = (-out[0] == out[1]) ? out[1] : 1;
1757: ISSetBlockSize((*fields)[f], bs);
1758: }
1759: }
1760: PetscFree3(fieldSizes,fieldNc,fieldIndices);
1761: } else if (dm->ops->createfieldis) {
1762: (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1763: }
1764: return(0);
1765: }
1768: /*@C
1769: DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1770: corresponding to different fields: each IS contains the global indices of the dofs of the
1771: corresponding field. The optional list of DMs define the DM for each subproblem.
1772: Generalizes DMCreateFieldIS().
1774: Not collective
1776: Input Parameter:
1777: . dm - the DM object
1779: Output Parameters:
1780: + len - The number of subproblems in the field decomposition (or NULL if not requested)
1781: . namelist - The name for each field (or NULL if not requested)
1782: . islist - The global indices for each field (or NULL if not requested)
1783: - dmlist - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1785: Level: intermediate
1787: Notes:
1788: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1789: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1790: and all of the arrays should be freed with PetscFree().
1792: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1793: @*/
1794: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1795: {
1800: if (len) {
1802: *len = 0;
1803: }
1804: if (namelist) {
1806: *namelist = NULL;
1807: }
1808: if (islist) {
1810: *islist = NULL;
1811: }
1812: if (dmlist) {
1814: *dmlist = NULL;
1815: }
1816: /*
1817: Is it a good idea to apply the following check across all impls?
1818: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1819: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1820: */
1821: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1822: if (!dm->ops->createfielddecomposition) {
1823: PetscSection section;
1824: PetscInt numFields, f;
1826: DMGetLocalSection(dm, §ion);
1827: if (section) {PetscSectionGetNumFields(section, &numFields);}
1828: if (section && numFields && dm->ops->createsubdm) {
1829: if (len) *len = numFields;
1830: if (namelist) {PetscMalloc1(numFields,namelist);}
1831: if (islist) {PetscMalloc1(numFields,islist);}
1832: if (dmlist) {PetscMalloc1(numFields,dmlist);}
1833: for (f = 0; f < numFields; ++f) {
1834: const char *fieldName;
1836: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1837: if (namelist) {
1838: PetscSectionGetFieldName(section, f, &fieldName);
1839: PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1840: }
1841: }
1842: } else {
1843: DMCreateFieldIS(dm, len, namelist, islist);
1844: /* By default there are no DMs associated with subproblems. */
1845: if (dmlist) *dmlist = NULL;
1846: }
1847: } else {
1848: (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1849: }
1850: return(0);
1851: }
1853: /*@
1854: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1855: The fields are defined by DMCreateFieldIS().
1857: Not collective
1859: Input Parameters:
1860: + dm - The DM object
1861: . numFields - The number of fields in this subproblem
1862: - fields - The field numbers of the selected fields
1864: Output Parameters:
1865: + is - The global indices for the subproblem
1866: - subdm - The DM for the subproblem
1868: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1870: Level: intermediate
1872: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1873: @*/
1874: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1875: {
1883: if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
1884: (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1885: return(0);
1886: }
1888: /*@C
1889: DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.
1891: Not collective
1893: Input Parameter:
1894: + dms - The DM objects
1895: - len - The number of DMs
1897: Output Parameters:
1898: + is - The global indices for the subproblem, or NULL
1899: - superdm - The DM for the superproblem
1901: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1903: Level: intermediate
1905: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1906: @*/
1907: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1908: {
1909: PetscInt i;
1917: if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1918: if (len) {
1919: DM dm = dms[0];
1920: if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1921: (*dm->ops->createsuperdm)(dms, len, is, superdm);
1922: }
1923: return(0);
1924: }
1927: /*@C
1928: DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1929: corresponding to restrictions to pairs nested subdomains: each IS contains the global
1930: indices of the dofs of the corresponding subdomains. The inner subdomains conceptually
1931: define a nonoverlapping covering, while outer subdomains can overlap.
1932: The optional list of DMs define the DM for each subproblem.
1934: Not collective
1936: Input Parameter:
1937: . dm - the DM object
1939: Output Parameters:
1940: + len - The number of subproblems in the domain decomposition (or NULL if not requested)
1941: . namelist - The name for each subdomain (or NULL if not requested)
1942: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1943: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1944: - dmlist - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1946: Level: intermediate
1948: Notes:
1949: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1950: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1951: and all of the arrays should be freed with PetscFree().
1953: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1954: @*/
1955: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1956: {
1957: PetscErrorCode ierr;
1958: DMSubDomainHookLink link;
1959: PetscInt i,l;
1968: /*
1969: Is it a good idea to apply the following check across all impls?
1970: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1971: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1972: */
1973: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1974: if (dm->ops->createdomaindecomposition) {
1975: (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1976: /* copy subdomain hooks and context over to the subdomain DMs */
1977: if (dmlist && *dmlist) {
1978: for (i = 0; i < l; i++) {
1979: for (link=dm->subdomainhook; link; link=link->next) {
1980: if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1981: }
1982: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1983: }
1984: }
1985: if (len) *len = l;
1986: }
1987: return(0);
1988: }
1991: /*@C
1992: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
1994: Not collective
1996: Input Parameters:
1997: + dm - the DM object
1998: . n - the number of subdomain scatters
1999: - subdms - the local subdomains
2001: Output Parameters:
2002: + n - the number of scatters returned
2003: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2004: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2005: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2007: Notes:
2008: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2009: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2010: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2011: solution and residual data.
2013: Level: developer
2015: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2016: @*/
2017: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2018: {
2024: if (!dm->ops->createddscatters) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateDomainDecompositionScatters",((PetscObject)dm)->type_name);
2025: (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2026: return(0);
2027: }
2029: /*@
2030: DMRefine - Refines a DM object
2032: Collective on dm
2034: Input Parameter:
2035: + dm - the DM object
2036: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2038: Output Parameter:
2039: . dmf - the refined DM, or NULL
2041: Options Dtabase Keys:
2042: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2044: Note: If no refinement was done, the return value is NULL
2046: Level: developer
2048: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2049: @*/
2050: PetscErrorCode DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2051: {
2052: PetscErrorCode ierr;
2053: DMRefineHookLink link;
2057: if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2058: PetscLogEventBegin(DM_Refine,dm,0,0,0);
2059: (*dm->ops->refine)(dm,comm,dmf);
2060: if (*dmf) {
2061: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2063: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);
2065: (*dmf)->ctx = dm->ctx;
2066: (*dmf)->leveldown = dm->leveldown;
2067: (*dmf)->levelup = dm->levelup + 1;
2069: DMSetMatType(*dmf,dm->mattype);
2070: for (link=dm->refinehook; link; link=link->next) {
2071: if (link->refinehook) {
2072: (*link->refinehook)(dm,*dmf,link->ctx);
2073: }
2074: }
2075: }
2076: PetscLogEventEnd(DM_Refine,dm,0,0,0);
2077: return(0);
2078: }
2080: /*@C
2081: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2083: Logically Collective
2085: Input Arguments:
2086: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2087: . refinehook - function to run when setting up a coarser level
2088: . interphook - function to run to update data on finer levels (once per SNESSolve())
2089: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2091: Calling sequence of refinehook:
2092: $ refinehook(DM coarse,DM fine,void *ctx);
2094: + coarse - coarse level DM
2095: . fine - fine level DM to interpolate problem to
2096: - ctx - optional user-defined function context
2098: Calling sequence for interphook:
2099: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2101: + coarse - coarse level DM
2102: . interp - matrix interpolating a coarse-level solution to the finer grid
2103: . fine - fine level DM to update
2104: - ctx - optional user-defined function context
2106: Level: advanced
2108: Notes:
2109: This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
2111: If this function is called multiple times, the hooks will be run in the order they are added.
2113: This function is currently not available from Fortran.
2115: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2116: @*/
2117: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2118: {
2119: PetscErrorCode ierr;
2120: DMRefineHookLink link,*p;
2124: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2125: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2126: }
2127: PetscNew(&link);
2128: link->refinehook = refinehook;
2129: link->interphook = interphook;
2130: link->ctx = ctx;
2131: link->next = NULL;
2132: *p = link;
2133: return(0);
2134: }
2136: /*@C
2137: DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
2139: Logically Collective
2141: Input Arguments:
2142: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2143: . refinehook - function to run when setting up a coarser level
2144: . interphook - function to run to update data on finer levels (once per SNESSolve())
2145: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2147: Level: advanced
2149: Notes:
2150: This function does nothing if the hook is not in the list.
2152: This function is currently not available from Fortran.
2154: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2155: @*/
2156: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2157: {
2158: PetscErrorCode ierr;
2159: DMRefineHookLink link,*p;
2163: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2164: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2165: link = *p;
2166: *p = link->next;
2167: PetscFree(link);
2168: break;
2169: }
2170: }
2171: return(0);
2172: }
2174: /*@
2175: DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
2177: Collective if any hooks are
2179: Input Arguments:
2180: + coarse - coarser DM to use as a base
2181: . interp - interpolation matrix, apply using MatInterpolate()
2182: - fine - finer DM to update
2184: Level: developer
2186: .seealso: DMRefineHookAdd(), MatInterpolate()
2187: @*/
2188: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2189: {
2190: PetscErrorCode ierr;
2191: DMRefineHookLink link;
2194: for (link=fine->refinehook; link; link=link->next) {
2195: if (link->interphook) {
2196: (*link->interphook)(coarse,interp,fine,link->ctx);
2197: }
2198: }
2199: return(0);
2200: }
2202: /*@
2203: DMGetRefineLevel - Gets the number of refinements that have generated this DM.
2205: Not Collective
2207: Input Parameter:
2208: . dm - the DM object
2210: Output Parameter:
2211: . level - number of refinements
2213: Level: developer
2215: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2217: @*/
2218: PetscErrorCode DMGetRefineLevel(DM dm,PetscInt *level)
2219: {
2222: *level = dm->levelup;
2223: return(0);
2224: }
2226: /*@
2227: DMSetRefineLevel - Sets the number of refinements that have generated this DM.
2229: Not Collective
2231: Input Parameter:
2232: + dm - the DM object
2233: - level - number of refinements
2235: Level: advanced
2237: Notes:
2238: This value is used by PCMG to determine how many multigrid levels to use
2240: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2242: @*/
2243: PetscErrorCode DMSetRefineLevel(DM dm,PetscInt level)
2244: {
2247: dm->levelup = level;
2248: return(0);
2249: }
2251: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2252: {
2256: *tdm = dm->transformDM;
2257: return(0);
2258: }
2260: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2261: {
2265: *tv = dm->transform;
2266: return(0);
2267: }
2269: /*@
2270: DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors
2272: Input Parameter:
2273: . dm - The DM
2275: Output Parameter:
2276: . flg - PETSC_TRUE if a basis transformation should be done
2278: Level: developer
2280: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2281: @*/
2282: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2283: {
2284: Vec tv;
2290: DMGetBasisTransformVec_Internal(dm, &tv);
2291: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2292: return(0);
2293: }
2295: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2296: {
2297: PetscSection s, ts;
2298: PetscScalar *ta;
2299: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2303: DMGetCoordinateDim(dm, &cdim);
2304: DMGetLocalSection(dm, &s);
2305: PetscSectionGetChart(s, &pStart, &pEnd);
2306: PetscSectionGetNumFields(s, &Nf);
2307: DMClone(dm, &dm->transformDM);
2308: DMGetLocalSection(dm->transformDM, &ts);
2309: PetscSectionSetNumFields(ts, Nf);
2310: PetscSectionSetChart(ts, pStart, pEnd);
2311: for (f = 0; f < Nf; ++f) {
2312: PetscSectionGetFieldComponents(s, f, &Nc);
2313: /* We could start to label fields by their transformation properties */
2314: if (Nc != cdim) continue;
2315: for (p = pStart; p < pEnd; ++p) {
2316: PetscSectionGetFieldDof(s, p, f, &dof);
2317: if (!dof) continue;
2318: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2319: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2320: }
2321: }
2322: PetscSectionSetUp(ts);
2323: DMCreateLocalVector(dm->transformDM, &dm->transform);
2324: VecGetArray(dm->transform, &ta);
2325: for (p = pStart; p < pEnd; ++p) {
2326: for (f = 0; f < Nf; ++f) {
2327: PetscSectionGetFieldDof(ts, p, f, &dof);
2328: if (dof) {
2329: PetscReal x[3] = {0.0, 0.0, 0.0};
2330: PetscScalar *tva;
2331: const PetscScalar *A;
2333: /* TODO Get quadrature point for this dual basis vector for coordinate */
2334: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2335: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2336: PetscArraycpy(tva, A, PetscSqr(cdim));
2337: }
2338: }
2339: }
2340: VecRestoreArray(dm->transform, &ta);
2341: return(0);
2342: }
2344: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2345: {
2351: newdm->transformCtx = dm->transformCtx;
2352: newdm->transformSetUp = dm->transformSetUp;
2353: newdm->transformDestroy = NULL;
2354: newdm->transformGetMatrix = dm->transformGetMatrix;
2355: if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2356: return(0);
2357: }
2359: /*@C
2360: DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
2362: Logically Collective
2364: Input Arguments:
2365: + dm - the DM
2366: . beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2367: . endhook - function to run after DMGlobalToLocalEnd() has completed
2368: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2370: Calling sequence for beginhook:
2371: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2373: + dm - global DM
2374: . g - global vector
2375: . mode - mode
2376: . l - local vector
2377: - ctx - optional user-defined function context
2380: Calling sequence for endhook:
2381: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2383: + global - global DM
2384: - ctx - optional user-defined function context
2386: Level: advanced
2388: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2389: @*/
2390: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2391: {
2392: PetscErrorCode ierr;
2393: DMGlobalToLocalHookLink link,*p;
2397: for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2398: PetscNew(&link);
2399: link->beginhook = beginhook;
2400: link->endhook = endhook;
2401: link->ctx = ctx;
2402: link->next = NULL;
2403: *p = link;
2404: return(0);
2405: }
2407: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2408: {
2409: Mat cMat;
2410: Vec cVec;
2411: PetscSection section, cSec;
2412: PetscInt pStart, pEnd, p, dof;
2417: DMGetDefaultConstraints(dm,&cSec,&cMat);
2418: if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2419: PetscInt nRows;
2421: MatGetSize(cMat,&nRows,NULL);
2422: if (nRows <= 0) return(0);
2423: DMGetLocalSection(dm,§ion);
2424: MatCreateVecs(cMat,NULL,&cVec);
2425: MatMult(cMat,l,cVec);
2426: PetscSectionGetChart(cSec,&pStart,&pEnd);
2427: for (p = pStart; p < pEnd; p++) {
2428: PetscSectionGetDof(cSec,p,&dof);
2429: if (dof) {
2430: PetscScalar *vals;
2431: VecGetValuesSection(cVec,cSec,p,&vals);
2432: VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2433: }
2434: }
2435: VecDestroy(&cVec);
2436: }
2437: return(0);
2438: }
2440: /*@
2441: DMGlobalToLocal - update local vectors from global vector
2443: Neighbor-wise Collective on dm
2445: Input Parameters:
2446: + dm - the DM object
2447: . g - the global vector
2448: . mode - INSERT_VALUES or ADD_VALUES
2449: - l - the local vector
2451: Notes:
2452: The communication involved in this update can be overlapped with computation by using
2453: DMGlobalToLocalBegin() and DMGlobalToLocalEnd().
2455: Level: beginner
2457: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2459: @*/
2460: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2461: {
2465: DMGlobalToLocalBegin(dm,g,mode,l);
2466: DMGlobalToLocalEnd(dm,g,mode,l);
2467: return(0);
2468: }
2470: /*@
2471: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2473: Neighbor-wise Collective on dm
2475: Input Parameters:
2476: + dm - the DM object
2477: . g - the global vector
2478: . mode - INSERT_VALUES or ADD_VALUES
2479: - l - the local vector
2481: Level: intermediate
2483: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2485: @*/
2486: PetscErrorCode DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2487: {
2488: PetscSF sf;
2489: PetscErrorCode ierr;
2490: DMGlobalToLocalHookLink link;
2494: for (link=dm->gtolhook; link; link=link->next) {
2495: if (link->beginhook) {
2496: (*link->beginhook)(dm,g,mode,l,link->ctx);
2497: }
2498: }
2499: DMGetSectionSF(dm, &sf);
2500: if (sf) {
2501: const PetscScalar *gArray;
2502: PetscScalar *lArray;
2504: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2505: VecGetArrayInPlace(l, &lArray);
2506: VecGetArrayReadInPlace(g, &gArray);
2507: PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
2508: VecRestoreArrayInPlace(l, &lArray);
2509: VecRestoreArrayReadInPlace(g, &gArray);
2510: } else {
2511: if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2512: (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2513: }
2514: return(0);
2515: }
2517: /*@
2518: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2520: Neighbor-wise Collective on dm
2522: Input Parameters:
2523: + dm - the DM object
2524: . g - the global vector
2525: . mode - INSERT_VALUES or ADD_VALUES
2526: - l - the local vector
2528: Level: intermediate
2530: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2532: @*/
2533: PetscErrorCode DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2534: {
2535: PetscSF sf;
2536: PetscErrorCode ierr;
2537: const PetscScalar *gArray;
2538: PetscScalar *lArray;
2539: PetscBool transform;
2540: DMGlobalToLocalHookLink link;
2544: DMGetSectionSF(dm, &sf);
2545: DMHasBasisTransform(dm, &transform);
2546: if (sf) {
2547: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2549: VecGetArrayInPlace(l, &lArray);
2550: VecGetArrayReadInPlace(g, &gArray);
2551: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2552: VecRestoreArrayInPlace(l, &lArray);
2553: VecRestoreArrayReadInPlace(g, &gArray);
2554: if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2555: } else {
2556: if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2557: (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2558: }
2559: DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2560: for (link=dm->gtolhook; link; link=link->next) {
2561: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2562: }
2563: return(0);
2564: }
2566: /*@C
2567: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2569: Logically Collective
2571: Input Arguments:
2572: + dm - the DM
2573: . beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2574: . endhook - function to run after DMLocalToGlobalEnd() has completed
2575: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2577: Calling sequence for beginhook:
2578: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2580: + dm - global DM
2581: . l - local vector
2582: . mode - mode
2583: . g - global vector
2584: - ctx - optional user-defined function context
2587: Calling sequence for endhook:
2588: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2590: + global - global DM
2591: . l - local vector
2592: . mode - mode
2593: . g - global vector
2594: - ctx - optional user-defined function context
2596: Level: advanced
2598: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2599: @*/
2600: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2601: {
2602: PetscErrorCode ierr;
2603: DMLocalToGlobalHookLink link,*p;
2607: for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2608: PetscNew(&link);
2609: link->beginhook = beginhook;
2610: link->endhook = endhook;
2611: link->ctx = ctx;
2612: link->next = NULL;
2613: *p = link;
2614: return(0);
2615: }
2617: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2618: {
2619: Mat cMat;
2620: Vec cVec;
2621: PetscSection section, cSec;
2622: PetscInt pStart, pEnd, p, dof;
2627: DMGetDefaultConstraints(dm,&cSec,&cMat);
2628: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2629: PetscInt nRows;
2631: MatGetSize(cMat,&nRows,NULL);
2632: if (nRows <= 0) return(0);
2633: DMGetLocalSection(dm,§ion);
2634: MatCreateVecs(cMat,NULL,&cVec);
2635: PetscSectionGetChart(cSec,&pStart,&pEnd);
2636: for (p = pStart; p < pEnd; p++) {
2637: PetscSectionGetDof(cSec,p,&dof);
2638: if (dof) {
2639: PetscInt d;
2640: PetscScalar *vals;
2641: VecGetValuesSection(l,section,p,&vals);
2642: VecSetValuesSection(cVec,cSec,p,vals,mode);
2643: /* for this to be the true transpose, we have to zero the values that
2644: * we just extracted */
2645: for (d = 0; d < dof; d++) {
2646: vals[d] = 0.;
2647: }
2648: }
2649: }
2650: MatMultTransposeAdd(cMat,cVec,l,l);
2651: VecDestroy(&cVec);
2652: }
2653: return(0);
2654: }
2655: /*@
2656: DMLocalToGlobal - updates global vectors from local vectors
2658: Neighbor-wise Collective on dm
2660: Input Parameters:
2661: + dm - the DM object
2662: . l - the local vector
2663: . 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.
2664: - g - the global vector
2666: Notes:
2667: The communication involved in this update can be overlapped with computation by using
2668: DMLocalToGlobalBegin() and DMLocalToGlobalEnd().
2670: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2671: INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.
2673: Level: beginner
2675: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2677: @*/
2678: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2679: {
2683: DMLocalToGlobalBegin(dm,l,mode,g);
2684: DMLocalToGlobalEnd(dm,l,mode,g);
2685: return(0);
2686: }
2688: /*@
2689: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2691: Neighbor-wise Collective on dm
2693: Input Parameters:
2694: + dm - the DM object
2695: . l - the local vector
2696: . 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.
2697: - g - the global vector
2699: Notes:
2700: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2701: INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2703: Level: intermediate
2705: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2707: @*/
2708: PetscErrorCode DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2709: {
2710: PetscSF sf;
2711: PetscSection s, gs;
2712: DMLocalToGlobalHookLink link;
2713: Vec tmpl;
2714: const PetscScalar *lArray;
2715: PetscScalar *gArray;
2716: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2717: PetscErrorCode ierr;
2721: for (link=dm->ltoghook; link; link=link->next) {
2722: if (link->beginhook) {
2723: (*link->beginhook)(dm,l,mode,g,link->ctx);
2724: }
2725: }
2726: DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2727: DMGetSectionSF(dm, &sf);
2728: DMGetLocalSection(dm, &s);
2729: switch (mode) {
2730: case INSERT_VALUES:
2731: case INSERT_ALL_VALUES:
2732: case INSERT_BC_VALUES:
2733: isInsert = PETSC_TRUE; break;
2734: case ADD_VALUES:
2735: case ADD_ALL_VALUES:
2736: case ADD_BC_VALUES:
2737: isInsert = PETSC_FALSE; break;
2738: default:
2739: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2740: }
2741: if ((sf && !isInsert) || (s && isInsert)) {
2742: DMHasBasisTransform(dm, &transform);
2743: if (transform) {
2744: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2745: VecCopy(l, tmpl);
2746: DMPlexLocalToGlobalBasis(dm, tmpl);
2747: VecGetArrayRead(tmpl, &lArray);
2748: } else if (isInsert) {
2749: VecGetArrayRead(l, &lArray);
2750: } else {
2751: VecGetArrayReadInPlace(l, &lArray);
2752: l_inplace = PETSC_TRUE;
2753: }
2754: if (s && isInsert) {
2755: VecGetArray(g, &gArray);
2756: } else {
2757: VecGetArrayInPlace(g, &gArray);
2758: g_inplace = PETSC_TRUE;
2759: }
2760: if (sf && !isInsert) {
2761: PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2762: } else if (s && isInsert) {
2763: PetscInt gStart, pStart, pEnd, p;
2765: DMGetGlobalSection(dm, &gs);
2766: PetscSectionGetChart(s, &pStart, &pEnd);
2767: VecGetOwnershipRange(g, &gStart, NULL);
2768: for (p = pStart; p < pEnd; ++p) {
2769: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2771: PetscSectionGetDof(s, p, &dof);
2772: PetscSectionGetDof(gs, p, &gdof);
2773: PetscSectionGetConstraintDof(s, p, &cdof);
2774: PetscSectionGetConstraintDof(gs, p, &gcdof);
2775: PetscSectionGetOffset(s, p, &off);
2776: PetscSectionGetOffset(gs, p, &goff);
2777: /* Ignore off-process data and points with no global data */
2778: if (!gdof || goff < 0) continue;
2779: 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);
2780: /* If no constraints are enforced in the global vector */
2781: if (!gcdof) {
2782: for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2783: /* If constraints are enforced in the global vector */
2784: } else if (cdof == gcdof) {
2785: const PetscInt *cdofs;
2786: PetscInt cind = 0;
2788: PetscSectionGetConstraintIndices(s, p, &cdofs);
2789: for (d = 0, e = 0; d < dof; ++d) {
2790: if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2791: gArray[goff-gStart+e++] = lArray[off+d];
2792: }
2793: } 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);
2794: }
2795: }
2796: if (g_inplace) {
2797: VecRestoreArrayInPlace(g, &gArray);
2798: } else {
2799: VecRestoreArray(g, &gArray);
2800: }
2801: if (transform) {
2802: VecRestoreArrayRead(tmpl, &lArray);
2803: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2804: } else if (l_inplace) {
2805: VecRestoreArrayReadInPlace(l, &lArray);
2806: } else {
2807: VecRestoreArrayRead(l, &lArray);
2808: }
2809: } else {
2810: if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2811: (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2812: }
2813: return(0);
2814: }
2816: /*@
2817: DMLocalToGlobalEnd - updates global vectors from local vectors
2819: Neighbor-wise Collective on dm
2821: Input Parameters:
2822: + dm - the DM object
2823: . l - the local vector
2824: . mode - INSERT_VALUES or ADD_VALUES
2825: - g - the global vector
2827: Level: intermediate
2829: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2831: @*/
2832: PetscErrorCode DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2833: {
2834: PetscSF sf;
2835: PetscSection s;
2836: DMLocalToGlobalHookLink link;
2837: PetscBool isInsert, transform;
2838: PetscErrorCode ierr;
2842: DMGetSectionSF(dm, &sf);
2843: DMGetLocalSection(dm, &s);
2844: switch (mode) {
2845: case INSERT_VALUES:
2846: case INSERT_ALL_VALUES:
2847: isInsert = PETSC_TRUE; break;
2848: case ADD_VALUES:
2849: case ADD_ALL_VALUES:
2850: isInsert = PETSC_FALSE; break;
2851: default:
2852: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2853: }
2854: if (sf && !isInsert) {
2855: const PetscScalar *lArray;
2856: PetscScalar *gArray;
2857: Vec tmpl;
2859: DMHasBasisTransform(dm, &transform);
2860: if (transform) {
2861: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2862: VecGetArrayRead(tmpl, &lArray);
2863: } else {
2864: VecGetArrayReadInPlace(l, &lArray);
2865: }
2866: VecGetArrayInPlace(g, &gArray);
2867: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2868: if (transform) {
2869: VecRestoreArrayRead(tmpl, &lArray);
2870: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2871: } else {
2872: VecRestoreArrayReadInPlace(l, &lArray);
2873: }
2874: VecRestoreArrayInPlace(g, &gArray);
2875: } else if (s && isInsert) {
2876: } else {
2877: if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2878: (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2879: }
2880: for (link=dm->ltoghook; link; link=link->next) {
2881: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2882: }
2883: return(0);
2884: }
2886: /*@
2887: DMLocalToLocalBegin - Maps from a local vector (including ghost points
2888: that contain irrelevant values) to another local vector where the ghost
2889: points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2891: Neighbor-wise Collective on dm
2893: Input Parameters:
2894: + dm - the DM object
2895: . g - the original local vector
2896: - mode - one of INSERT_VALUES or ADD_VALUES
2898: Output Parameter:
2899: . l - the local vector with correct ghost values
2901: Level: intermediate
2903: Notes:
2904: The local vectors used here need not be the same as those
2905: obtained from DMCreateLocalVector(), BUT they
2906: must have the same parallel data layout; they could, for example, be
2907: obtained with VecDuplicate() from the DM originating vectors.
2909: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2911: @*/
2912: PetscErrorCode DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2913: {
2914: PetscErrorCode ierr;
2918: if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2919: (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2920: return(0);
2921: }
2923: /*@
2924: DMLocalToLocalEnd - Maps from a local vector (including ghost points
2925: that contain irrelevant values) to another local vector where the ghost
2926: points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2928: Neighbor-wise Collective on dm
2930: Input Parameters:
2931: + da - the DM object
2932: . g - the original local vector
2933: - mode - one of INSERT_VALUES or ADD_VALUES
2935: Output Parameter:
2936: . l - the local vector with correct ghost values
2938: Level: intermediate
2940: Notes:
2941: The local vectors used here need not be the same as those
2942: obtained from DMCreateLocalVector(), BUT they
2943: must have the same parallel data layout; they could, for example, be
2944: obtained with VecDuplicate() from the DM originating vectors.
2946: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2948: @*/
2949: PetscErrorCode DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2950: {
2951: PetscErrorCode ierr;
2955: if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2956: (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2957: return(0);
2958: }
2961: /*@
2962: DMCoarsen - Coarsens a DM object
2964: Collective on dm
2966: Input Parameter:
2967: + dm - the DM object
2968: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2970: Output Parameter:
2971: . dmc - the coarsened DM
2973: Level: developer
2975: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2977: @*/
2978: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2979: {
2980: PetscErrorCode ierr;
2981: DMCoarsenHookLink link;
2985: if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
2986: PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2987: (*dm->ops->coarsen)(dm, comm, dmc);
2988: if (*dmc) {
2989: DMSetCoarseDM(dm,*dmc);
2990: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2991: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2992: (*dmc)->ctx = dm->ctx;
2993: (*dmc)->levelup = dm->levelup;
2994: (*dmc)->leveldown = dm->leveldown + 1;
2995: DMSetMatType(*dmc,dm->mattype);
2996: for (link=dm->coarsenhook; link; link=link->next) {
2997: if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2998: }
2999: }
3000: PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3001: if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3002: return(0);
3003: }
3005: /*@C
3006: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3008: Logically Collective
3010: Input Arguments:
3011: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3012: . coarsenhook - function to run when setting up a coarser level
3013: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3014: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3016: Calling sequence of coarsenhook:
3017: $ coarsenhook(DM fine,DM coarse,void *ctx);
3019: + fine - fine level DM
3020: . coarse - coarse level DM to restrict problem to
3021: - ctx - optional user-defined function context
3023: Calling sequence for restricthook:
3024: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3026: + fine - fine level DM
3027: . mrestrict - matrix restricting a fine-level solution to the coarse grid
3028: . rscale - scaling vector for restriction
3029: . inject - matrix restricting by injection
3030: . coarse - coarse level DM to update
3031: - ctx - optional user-defined function context
3033: Level: advanced
3035: Notes:
3036: This function is only needed if auxiliary data needs to be set up on coarse grids.
3038: If this function is called multiple times, the hooks will be run in the order they are added.
3040: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3041: extract the finest level information from its context (instead of from the SNES).
3043: This function is currently not available from Fortran.
3045: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3046: @*/
3047: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3048: {
3049: PetscErrorCode ierr;
3050: DMCoarsenHookLink link,*p;
3054: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3055: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3056: }
3057: PetscNew(&link);
3058: link->coarsenhook = coarsenhook;
3059: link->restricthook = restricthook;
3060: link->ctx = ctx;
3061: link->next = NULL;
3062: *p = link;
3063: return(0);
3064: }
3066: /*@C
3067: DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
3069: Logically Collective
3071: Input Arguments:
3072: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3073: . coarsenhook - function to run when setting up a coarser level
3074: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3075: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3077: Level: advanced
3079: Notes:
3080: This function does nothing if the hook is not in the list.
3082: This function is currently not available from Fortran.
3084: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3085: @*/
3086: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3087: {
3088: PetscErrorCode ierr;
3089: DMCoarsenHookLink link,*p;
3093: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3094: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3095: link = *p;
3096: *p = link->next;
3097: PetscFree(link);
3098: break;
3099: }
3100: }
3101: return(0);
3102: }
3105: /*@
3106: DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
3108: Collective if any hooks are
3110: Input Arguments:
3111: + fine - finer DM to use as a base
3112: . restrct - restriction matrix, apply using MatRestrict()
3113: . rscale - scaling vector for restriction
3114: . inject - injection matrix, also use MatRestrict()
3115: - coarse - coarser DM to update
3117: Level: developer
3119: .seealso: DMCoarsenHookAdd(), MatRestrict()
3120: @*/
3121: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3122: {
3123: PetscErrorCode ierr;
3124: DMCoarsenHookLink link;
3127: for (link=fine->coarsenhook; link; link=link->next) {
3128: if (link->restricthook) {
3129: (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3130: }
3131: }
3132: return(0);
3133: }
3135: /*@C
3136: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3138: Logically Collective on global
3140: Input Arguments:
3141: + global - global DM
3142: . ddhook - function to run to pass data to the decomposition DM upon its creation
3143: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3144: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3147: Calling sequence for ddhook:
3148: $ ddhook(DM global,DM block,void *ctx)
3150: + global - global DM
3151: . block - block DM
3152: - ctx - optional user-defined function context
3154: Calling sequence for restricthook:
3155: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3157: + global - global DM
3158: . out - scatter to the outer (with ghost and overlap points) block vector
3159: . in - scatter to block vector values only owned locally
3160: . block - block DM
3161: - ctx - optional user-defined function context
3163: Level: advanced
3165: Notes:
3166: This function is only needed if auxiliary data needs to be set up on subdomain DMs.
3168: If this function is called multiple times, the hooks will be run in the order they are added.
3170: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3171: extract the global information from its context (instead of from the SNES).
3173: This function is currently not available from Fortran.
3175: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3176: @*/
3177: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3178: {
3179: PetscErrorCode ierr;
3180: DMSubDomainHookLink link,*p;
3184: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3185: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3186: }
3187: PetscNew(&link);
3188: link->restricthook = restricthook;
3189: link->ddhook = ddhook;
3190: link->ctx = ctx;
3191: link->next = NULL;
3192: *p = link;
3193: return(0);
3194: }
3196: /*@C
3197: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3199: Logically Collective
3201: Input Arguments:
3202: + global - global DM
3203: . ddhook - function to run to pass data to the decomposition DM upon its creation
3204: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3205: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3207: Level: advanced
3209: Notes:
3211: This function is currently not available from Fortran.
3213: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3214: @*/
3215: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3216: {
3217: PetscErrorCode ierr;
3218: DMSubDomainHookLink link,*p;
3222: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3223: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3224: link = *p;
3225: *p = link->next;
3226: PetscFree(link);
3227: break;
3228: }
3229: }
3230: return(0);
3231: }
3233: /*@
3234: DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
3236: Collective if any hooks are
3238: Input Arguments:
3239: + fine - finer DM to use as a base
3240: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3241: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3242: - coarse - coarer DM to update
3244: Level: developer
3246: .seealso: DMCoarsenHookAdd(), MatRestrict()
3247: @*/
3248: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3249: {
3250: PetscErrorCode ierr;
3251: DMSubDomainHookLink link;
3254: for (link=global->subdomainhook; link; link=link->next) {
3255: if (link->restricthook) {
3256: (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3257: }
3258: }
3259: return(0);
3260: }
3262: /*@
3263: DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
3265: Not Collective
3267: Input Parameter:
3268: . dm - the DM object
3270: Output Parameter:
3271: . level - number of coarsenings
3273: Level: developer
3275: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3277: @*/
3278: PetscErrorCode DMGetCoarsenLevel(DM dm,PetscInt *level)
3279: {
3283: *level = dm->leveldown;
3284: return(0);
3285: }
3287: /*@
3288: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
3290: Not Collective
3292: Input Parameters:
3293: + dm - the DM object
3294: - level - number of coarsenings
3296: Level: developer
3298: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3299: @*/
3300: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3301: {
3304: dm->leveldown = level;
3305: return(0);
3306: }
3310: /*@C
3311: DMRefineHierarchy - Refines a DM object, all levels at once
3313: Collective on dm
3315: Input Parameter:
3316: + dm - the DM object
3317: - nlevels - the number of levels of refinement
3319: Output Parameter:
3320: . dmf - the refined DM hierarchy
3322: Level: developer
3324: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3326: @*/
3327: PetscErrorCode DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3328: {
3333: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3334: if (nlevels == 0) return(0);
3336: if (dm->ops->refinehierarchy) {
3337: (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3338: } else if (dm->ops->refine) {
3339: PetscInt i;
3341: DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3342: for (i=1; i<nlevels; i++) {
3343: DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3344: }
3345: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3346: return(0);
3347: }
3349: /*@C
3350: DMCoarsenHierarchy - Coarsens a DM object, all levels at once
3352: Collective on dm
3354: Input Parameter:
3355: + dm - the DM object
3356: - nlevels - the number of levels of coarsening
3358: Output Parameter:
3359: . dmc - the coarsened DM hierarchy
3361: Level: developer
3363: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3365: @*/
3366: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3367: {
3372: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3373: if (nlevels == 0) return(0);
3375: if (dm->ops->coarsenhierarchy) {
3376: (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3377: } else if (dm->ops->coarsen) {
3378: PetscInt i;
3380: DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3381: for (i=1; i<nlevels; i++) {
3382: DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3383: }
3384: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3385: return(0);
3386: }
3388: /*@C
3389: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
3391: Not Collective
3393: Input Parameters:
3394: + dm - the DM object
3395: - destroy - the destroy function
3397: Level: intermediate
3399: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3401: @*/
3402: PetscErrorCode DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3403: {
3406: dm->ctxdestroy = destroy;
3407: return(0);
3408: }
3410: /*@
3411: DMSetApplicationContext - Set a user context into a DM object
3413: Not Collective
3415: Input Parameters:
3416: + dm - the DM object
3417: - ctx - the user context
3419: Level: intermediate
3421: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3423: @*/
3424: PetscErrorCode DMSetApplicationContext(DM dm,void *ctx)
3425: {
3428: dm->ctx = ctx;
3429: return(0);
3430: }
3432: /*@
3433: DMGetApplicationContext - Gets a user context from a DM object
3435: Not Collective
3437: Input Parameter:
3438: . dm - the DM object
3440: Output Parameter:
3441: . ctx - the user context
3443: Level: intermediate
3445: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3447: @*/
3448: PetscErrorCode DMGetApplicationContext(DM dm,void *ctx)
3449: {
3452: *(void**)ctx = dm->ctx;
3453: return(0);
3454: }
3456: /*@C
3457: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3459: Logically Collective on dm
3461: Input Parameter:
3462: + dm - the DM object
3463: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3465: Level: intermediate
3467: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3468: DMSetJacobian()
3470: @*/
3471: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3472: {
3475: dm->ops->computevariablebounds = f;
3476: return(0);
3477: }
3479: /*@
3480: DMHasVariableBounds - does the DM object have a variable bounds function?
3482: Not Collective
3484: Input Parameter:
3485: . dm - the DM object to destroy
3487: Output Parameter:
3488: . flg - PETSC_TRUE if the variable bounds function exists
3490: Level: developer
3492: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3494: @*/
3495: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3496: {
3500: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3501: return(0);
3502: }
3504: /*@C
3505: DMComputeVariableBounds - compute variable bounds used by SNESVI.
3507: Logically Collective on dm
3509: Input Parameters:
3510: . dm - the DM object
3512: Output parameters:
3513: + xl - lower bound
3514: - xu - upper bound
3516: Level: advanced
3518: Notes:
3519: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3521: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3523: @*/
3524: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3525: {
3532: if (!dm->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeVariableBounds",((PetscObject)dm)->type_name);
3533: (*dm->ops->computevariablebounds)(dm, xl,xu);
3534: return(0);
3535: }
3537: /*@
3538: DMHasColoring - does the DM object have a method of providing a coloring?
3540: Not Collective
3542: Input Parameter:
3543: . dm - the DM object
3545: Output Parameter:
3546: . flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3548: Level: developer
3550: .seealso DMCreateColoring()
3552: @*/
3553: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3554: {
3558: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3559: return(0);
3560: }
3562: /*@
3563: DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3565: Not Collective
3567: Input Parameter:
3568: . dm - the DM object
3570: Output Parameter:
3571: . flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3573: Level: developer
3575: .seealso DMCreateRestriction()
3577: @*/
3578: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3579: {
3583: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3584: return(0);
3585: }
3588: /*@
3589: DMHasCreateInjection - does the DM object have a method of providing an injection?
3591: Not Collective
3593: Input Parameter:
3594: . dm - the DM object
3596: Output Parameter:
3597: . flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3599: Level: developer
3601: .seealso DMCreateInjection()
3603: @*/
3604: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3605: {
3611: if (dm->ops->hascreateinjection) {
3612: (*dm->ops->hascreateinjection)(dm,flg);
3613: } else {
3614: *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3615: }
3616: return(0);
3617: }
3619: PetscFunctionList DMList = NULL;
3620: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3622: /*@C
3623: DMSetType - Builds a DM, for a particular DM implementation.
3625: Collective on dm
3627: Input Parameters:
3628: + dm - The DM object
3629: - method - The name of the DM type
3631: Options Database Key:
3632: . -dm_type <type> - Sets the DM type; use -help for a list of available types
3634: Notes:
3635: See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3637: Level: intermediate
3639: .seealso: DMGetType(), DMCreate()
3640: @*/
3641: PetscErrorCode DMSetType(DM dm, DMType method)
3642: {
3643: PetscErrorCode (*r)(DM);
3644: PetscBool match;
3649: PetscObjectTypeCompare((PetscObject) dm, method, &match);
3650: if (match) return(0);
3652: DMRegisterAll();
3653: PetscFunctionListFind(DMList,method,&r);
3654: if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3656: if (dm->ops->destroy) {
3657: (*dm->ops->destroy)(dm);
3658: }
3659: PetscMemzero(dm->ops,sizeof(*dm->ops));
3660: PetscObjectChangeTypeName((PetscObject)dm,method);
3661: (*r)(dm);
3662: return(0);
3663: }
3665: /*@C
3666: DMGetType - Gets the DM type name (as a string) from the DM.
3668: Not Collective
3670: Input Parameter:
3671: . dm - The DM
3673: Output Parameter:
3674: . type - The DM type name
3676: Level: intermediate
3678: .seealso: DMSetType(), DMCreate()
3679: @*/
3680: PetscErrorCode DMGetType(DM dm, DMType *type)
3681: {
3687: DMRegisterAll();
3688: *type = ((PetscObject)dm)->type_name;
3689: return(0);
3690: }
3692: /*@C
3693: DMConvert - Converts a DM to another DM, either of the same or different type.
3695: Collective on dm
3697: Input Parameters:
3698: + dm - the DM
3699: - newtype - new DM type (use "same" for the same type)
3701: Output Parameter:
3702: . M - pointer to new DM
3704: Notes:
3705: Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3706: the MPI communicator of the generated DM is always the same as the communicator
3707: of the input DM.
3709: Level: intermediate
3711: .seealso: DMCreate()
3712: @*/
3713: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3714: {
3715: DM B;
3716: char convname[256];
3717: PetscBool sametype/*, issame */;
3724: PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3725: /* PetscStrcmp(newtype, "same", &issame); */
3726: if (sametype) {
3727: *M = dm;
3728: PetscObjectReference((PetscObject) dm);
3729: return(0);
3730: } else {
3731: PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3733: /*
3734: Order of precedence:
3735: 1) See if a specialized converter is known to the current DM.
3736: 2) See if a specialized converter is known to the desired DM class.
3737: 3) See if a good general converter is registered for the desired class
3738: 4) See if a good general converter is known for the current matrix.
3739: 5) Use a really basic converter.
3740: */
3742: /* 1) See if a specialized converter is known to the current DM and the desired class */
3743: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3744: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3745: PetscStrlcat(convname,"_",sizeof(convname));
3746: PetscStrlcat(convname,newtype,sizeof(convname));
3747: PetscStrlcat(convname,"_C",sizeof(convname));
3748: PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3749: if (conv) goto foundconv;
3751: /* 2) See if a specialized converter is known to the desired DM class. */
3752: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3753: DMSetType(B, newtype);
3754: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3755: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3756: PetscStrlcat(convname,"_",sizeof(convname));
3757: PetscStrlcat(convname,newtype,sizeof(convname));
3758: PetscStrlcat(convname,"_C",sizeof(convname));
3759: PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3760: if (conv) {
3761: DMDestroy(&B);
3762: goto foundconv;
3763: }
3765: #if 0
3766: /* 3) See if a good general converter is registered for the desired class */
3767: conv = B->ops->convertfrom;
3768: DMDestroy(&B);
3769: if (conv) goto foundconv;
3771: /* 4) See if a good general converter is known for the current matrix */
3772: if (dm->ops->convert) {
3773: conv = dm->ops->convert;
3774: }
3775: if (conv) goto foundconv;
3776: #endif
3778: /* 5) Use a really basic converter. */
3779: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3781: foundconv:
3782: PetscLogEventBegin(DM_Convert,dm,0,0,0);
3783: (*conv)(dm,newtype,M);
3784: /* Things that are independent of DM type: We should consult DMClone() here */
3785: {
3786: PetscBool isper;
3787: const PetscReal *maxCell, *L;
3788: const DMBoundaryType *bd;
3789: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3790: DMSetPeriodicity(*M, isper, maxCell, L, bd);
3791: }
3792: PetscLogEventEnd(DM_Convert,dm,0,0,0);
3793: }
3794: PetscObjectStateIncrease((PetscObject) *M);
3795: return(0);
3796: }
3798: /*--------------------------------------------------------------------------------------------------------------------*/
3800: /*@C
3801: DMRegister - Adds a new DM component implementation
3803: Not Collective
3805: Input Parameters:
3806: + name - The name of a new user-defined creation routine
3807: - create_func - The creation routine itself
3809: Notes:
3810: DMRegister() may be called multiple times to add several user-defined DMs
3813: Sample usage:
3814: .vb
3815: DMRegister("my_da", MyDMCreate);
3816: .ve
3818: Then, your DM type can be chosen with the procedural interface via
3819: .vb
3820: DMCreate(MPI_Comm, DM *);
3821: DMSetType(DM,"my_da");
3822: .ve
3823: or at runtime via the option
3824: .vb
3825: -da_type my_da
3826: .ve
3828: Level: advanced
3830: .seealso: DMRegisterAll(), DMRegisterDestroy()
3832: @*/
3833: PetscErrorCode DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3834: {
3838: DMInitializePackage();
3839: PetscFunctionListAdd(&DMList,sname,function);
3840: return(0);
3841: }
3843: /*@C
3844: DMLoad - Loads a DM that has been stored in binary with DMView().
3846: Collective on viewer
3848: Input Parameters:
3849: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3850: some related function before a call to DMLoad().
3851: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3852: HDF5 file viewer, obtained from PetscViewerHDF5Open()
3854: Level: intermediate
3856: Notes:
3857: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3859: Notes for advanced users:
3860: Most users should not need to know the details of the binary storage
3861: format, since DMLoad() and DMView() completely hide these details.
3862: But for anyone who's interested, the standard binary matrix storage
3863: format is
3864: .vb
3865: has not yet been determined
3866: .ve
3868: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3869: @*/
3870: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
3871: {
3872: PetscBool isbinary, ishdf5;
3878: PetscViewerCheckReadable(viewer);
3879: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3880: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3881: PetscLogEventBegin(DM_Load,viewer,0,0,0);
3882: if (isbinary) {
3883: PetscInt classid;
3884: char type[256];
3886: PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3887: if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3888: PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3889: DMSetType(newdm, type);
3890: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3891: } else if (ishdf5) {
3892: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3893: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3894: PetscLogEventEnd(DM_Load,viewer,0,0,0);
3895: return(0);
3896: }
3898: /*@
3899: DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
3901: Not collective
3903: Input Parameter:
3904: . dm - the DM
3906: Output Parameters:
3907: + lmin - local minimum coordinates (length coord dim, optional)
3908: - lmax - local maximim coordinates (length coord dim, optional)
3910: Level: beginner
3912: Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
3915: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3916: @*/
3917: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3918: {
3919: Vec coords = NULL;
3920: PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3921: PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3922: const PetscScalar *local_coords;
3923: PetscInt N, Ni;
3924: PetscInt cdim, i, j;
3925: PetscErrorCode ierr;
3929: DMGetCoordinateDim(dm, &cdim);
3930: DMGetCoordinates(dm, &coords);
3931: if (coords) {
3932: VecGetArrayRead(coords, &local_coords);
3933: VecGetLocalSize(coords, &N);
3934: Ni = N/cdim;
3935: for (i = 0; i < Ni; ++i) {
3936: for (j = 0; j < 3; ++j) {
3937: min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3938: max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3939: }
3940: }
3941: VecRestoreArrayRead(coords, &local_coords);
3942: } else {
3943: PetscBool isda;
3945: PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3946: if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3947: }
3948: if (lmin) {PetscArraycpy(lmin, min, cdim);}
3949: if (lmax) {PetscArraycpy(lmax, max, cdim);}
3950: return(0);
3951: }
3953: /*@
3954: DMGetBoundingBox - Returns the global bounding box for the DM.
3956: Collective
3958: Input Parameter:
3959: . dm - the DM
3961: Output Parameters:
3962: + gmin - global minimum coordinates (length coord dim, optional)
3963: - gmax - global maximim coordinates (length coord dim, optional)
3965: Level: beginner
3967: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3968: @*/
3969: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3970: {
3971: PetscReal lmin[3], lmax[3];
3972: PetscInt cdim;
3973: PetscMPIInt count;
3978: DMGetCoordinateDim(dm, &cdim);
3979: PetscMPIIntCast(cdim, &count);
3980: DMGetLocalBoundingBox(dm, lmin, lmax);
3981: if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3982: if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3983: return(0);
3984: }
3986: /******************************** FEM Support **********************************/
3988: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3989: {
3990: PetscInt f;
3994: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3995: for (f = 0; f < len; ++f) {
3996: PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
3997: }
3998: return(0);
3999: }
4001: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4002: {
4003: PetscInt f, g;
4007: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4008: for (f = 0; f < rows; ++f) {
4009: PetscPrintf(PETSC_COMM_SELF, " |");
4010: for (g = 0; g < cols; ++g) {
4011: PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4012: }
4013: PetscPrintf(PETSC_COMM_SELF, " |\n");
4014: }
4015: return(0);
4016: }
4018: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4019: {
4020: PetscInt localSize, bs;
4021: PetscMPIInt size;
4022: Vec x, xglob;
4023: const PetscScalar *xarray;
4024: PetscErrorCode ierr;
4027: MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4028: VecDuplicate(X, &x);
4029: VecCopy(X, x);
4030: VecChop(x, tol);
4031: PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4032: if (size > 1) {
4033: VecGetLocalSize(x,&localSize);
4034: VecGetArrayRead(x,&xarray);
4035: VecGetBlockSize(x,&bs);
4036: VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4037: } else {
4038: xglob = x;
4039: }
4040: VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4041: if (size > 1) {
4042: VecDestroy(&xglob);
4043: VecRestoreArrayRead(x,&xarray);
4044: }
4045: VecDestroy(&x);
4046: return(0);
4047: }
4049: /*@
4050: DMGetSection - Get the PetscSection encoding the local data layout for the DM. This is equivalent to DMGetLocalSection(). Deprecated in v3.12
4052: Input Parameter:
4053: . dm - The DM
4055: Output Parameter:
4056: . section - The PetscSection
4058: Options Database Keys:
4059: . -dm_petscsection_view - View the Section created by the DM
4061: Level: advanced
4063: Notes:
4064: Use DMGetLocalSection() in new code.
4066: This gets a borrowed reference, so the user should not destroy this PetscSection.
4068: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4069: @*/
4070: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4071: {
4075: DMGetLocalSection(dm,section);
4076: return(0);
4077: }
4079: /*@
4080: DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
4082: Input Parameter:
4083: . dm - The DM
4085: Output Parameter:
4086: . section - The PetscSection
4088: Options Database Keys:
4089: . -dm_petscsection_view - View the Section created by the DM
4091: Level: intermediate
4093: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4095: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4096: @*/
4097: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4098: {
4104: if (!dm->localSection && dm->ops->createlocalsection) {
4105: PetscInt d;
4107: if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4108: (*dm->ops->createlocalsection)(dm);
4109: if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4110: }
4111: *section = dm->localSection;
4112: return(0);
4113: }
4115: /*@
4116: DMSetSection - Set the PetscSection encoding the local data layout for the DM. This is equivalent to DMSetLocalSection(). Deprecated in v3.12
4118: Input Parameters:
4119: + dm - The DM
4120: - section - The PetscSection
4122: Level: advanced
4124: Notes:
4125: Use DMSetLocalSection() in new code.
4127: Any existing Section will be destroyed
4129: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4130: @*/
4131: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4132: {
4136: DMSetLocalSection(dm,section);
4137: return(0);
4138: }
4140: /*@
4141: DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
4143: Input Parameters:
4144: + dm - The DM
4145: - section - The PetscSection
4147: Level: intermediate
4149: Note: Any existing Section will be destroyed
4151: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4152: @*/
4153: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4154: {
4155: PetscInt numFields = 0;
4156: PetscInt f;
4162: PetscObjectReference((PetscObject)section);
4163: PetscSectionDestroy(&dm->localSection);
4164: dm->localSection = section;
4165: if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4166: if (numFields) {
4167: DMSetNumFields(dm, numFields);
4168: for (f = 0; f < numFields; ++f) {
4169: PetscObject disc;
4170: const char *name;
4172: PetscSectionGetFieldName(dm->localSection, f, &name);
4173: DMGetField(dm, f, NULL, &disc);
4174: PetscObjectSetName(disc, name);
4175: }
4176: }
4177: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4178: PetscSectionDestroy(&dm->globalSection);
4179: return(0);
4180: }
4182: /*@
4183: DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4185: not collective
4187: Input Parameter:
4188: . dm - The DM
4190: Output Parameter:
4191: + 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.
4192: - 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.
4194: Level: advanced
4196: Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
4198: .seealso: DMSetDefaultConstraints()
4199: @*/
4200: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4201: {
4206: if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4207: if (section) {*section = dm->defaultConstraintSection;}
4208: if (mat) {*mat = dm->defaultConstraintMat;}
4209: return(0);
4210: }
4212: /*@
4213: DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4215: 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().
4217: 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.
4219: collective on dm
4221: Input Parameters:
4222: + dm - The DM
4223: + 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).
4224: - 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).
4226: Level: advanced
4228: Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
4230: .seealso: DMGetDefaultConstraints()
4231: @*/
4232: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4233: {
4234: PetscMPIInt result;
4239: if (section) {
4241: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4242: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4243: }
4244: if (mat) {
4246: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4247: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4248: }
4249: PetscObjectReference((PetscObject)section);
4250: PetscSectionDestroy(&dm->defaultConstraintSection);
4251: dm->defaultConstraintSection = section;
4252: PetscObjectReference((PetscObject)mat);
4253: MatDestroy(&dm->defaultConstraintMat);
4254: dm->defaultConstraintMat = mat;
4255: return(0);
4256: }
4258: #if defined(PETSC_USE_DEBUG)
4259: /*
4260: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4262: Input Parameters:
4263: + dm - The DM
4264: . localSection - PetscSection describing the local data layout
4265: - globalSection - PetscSection describing the global data layout
4267: Level: intermediate
4269: .seealso: DMGetSectionSF(), DMSetSectionSF()
4270: */
4271: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4272: {
4273: MPI_Comm comm;
4274: PetscLayout layout;
4275: const PetscInt *ranges;
4276: PetscInt pStart, pEnd, p, nroots;
4277: PetscMPIInt size, rank;
4278: PetscBool valid = PETSC_TRUE, gvalid;
4279: PetscErrorCode ierr;
4282: PetscObjectGetComm((PetscObject)dm,&comm);
4284: MPI_Comm_size(comm, &size);
4285: MPI_Comm_rank(comm, &rank);
4286: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4287: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4288: PetscLayoutCreate(comm, &layout);
4289: PetscLayoutSetBlockSize(layout, 1);
4290: PetscLayoutSetLocalSize(layout, nroots);
4291: PetscLayoutSetUp(layout);
4292: PetscLayoutGetRanges(layout, &ranges);
4293: for (p = pStart; p < pEnd; ++p) {
4294: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4296: PetscSectionGetDof(localSection, p, &dof);
4297: PetscSectionGetOffset(localSection, p, &off);
4298: PetscSectionGetConstraintDof(localSection, p, &cdof);
4299: PetscSectionGetDof(globalSection, p, &gdof);
4300: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4301: PetscSectionGetOffset(globalSection, p, &goff);
4302: if (!gdof) continue; /* Censored point */
4303: 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;}
4304: 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;}
4305: if (gdof < 0) {
4306: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4307: for (d = 0; d < gsize; ++d) {
4308: PetscInt offset = -(goff+1) + d, r;
4310: PetscFindInt(offset,size+1,ranges,&r);
4311: if (r < 0) r = -(r+2);
4312: 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;}
4313: }
4314: }
4315: }
4316: PetscLayoutDestroy(&layout);
4317: PetscSynchronizedFlush(comm, NULL);
4318: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4319: if (!gvalid) {
4320: DMView(dm, NULL);
4321: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4322: }
4323: return(0);
4324: }
4325: #endif
4327: /*@
4328: DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4330: Collective on dm
4332: Input Parameter:
4333: . dm - The DM
4335: Output Parameter:
4336: . section - The PetscSection
4338: Level: intermediate
4340: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4342: .seealso: DMSetLocalSection(), DMGetLocalSection()
4343: @*/
4344: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4345: {
4351: if (!dm->globalSection) {
4352: PetscSection s;
4354: DMGetLocalSection(dm, &s);
4355: if (!s) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4356: if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4357: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4358: PetscLayoutDestroy(&dm->map);
4359: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4360: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4361: }
4362: *section = dm->globalSection;
4363: return(0);
4364: }
4366: /*@
4367: DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4369: Input Parameters:
4370: + dm - The DM
4371: - section - The PetscSection, or NULL
4373: Level: intermediate
4375: Note: Any existing Section will be destroyed
4377: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4378: @*/
4379: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4380: {
4386: PetscObjectReference((PetscObject)section);
4387: PetscSectionDestroy(&dm->globalSection);
4388: dm->globalSection = section;
4389: #if defined(PETSC_USE_DEBUG)
4390: if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4391: #endif
4392: return(0);
4393: }
4395: /*@
4396: DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4397: it is created from the default PetscSection layouts in the DM.
4399: Input Parameter:
4400: . dm - The DM
4402: Output Parameter:
4403: . sf - The PetscSF
4405: Level: intermediate
4407: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4409: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4410: @*/
4411: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4412: {
4413: PetscInt nroots;
4419: if (!dm->sectionSF) {
4420: PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4421: }
4422: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4423: if (nroots < 0) {
4424: PetscSection section, gSection;
4426: DMGetLocalSection(dm, §ion);
4427: if (section) {
4428: DMGetGlobalSection(dm, &gSection);
4429: DMCreateSectionSF(dm, section, gSection);
4430: } else {
4431: *sf = NULL;
4432: return(0);
4433: }
4434: }
4435: *sf = dm->sectionSF;
4436: return(0);
4437: }
4439: /*@
4440: DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4442: Input Parameters:
4443: + dm - The DM
4444: - sf - The PetscSF
4446: Level: intermediate
4448: Note: Any previous SF is destroyed
4450: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4451: @*/
4452: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4453: {
4459: PetscObjectReference((PetscObject) sf);
4460: PetscSFDestroy(&dm->sectionSF);
4461: dm->sectionSF = sf;
4462: return(0);
4463: }
4465: /*@C
4466: DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4467: describing the data layout.
4469: Input Parameters:
4470: + dm - The DM
4471: . localSection - PetscSection describing the local data layout
4472: - globalSection - PetscSection describing the global data layout
4474: Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4476: Level: developer
4478: Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4479: directly into the DM, perhaps this function should not take the local and global sections as
4480: input and should just obtain them from the DM?
4482: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4483: @*/
4484: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4485: {
4486: MPI_Comm comm;
4487: PetscLayout layout;
4488: const PetscInt *ranges;
4489: PetscInt *local;
4490: PetscSFNode *remote;
4491: PetscInt pStart, pEnd, p, nroots, nleaves = 0, l;
4492: PetscMPIInt size, rank;
4497: PetscObjectGetComm((PetscObject)dm,&comm);
4498: MPI_Comm_size(comm, &size);
4499: MPI_Comm_rank(comm, &rank);
4500: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4501: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4502: PetscLayoutCreate(comm, &layout);
4503: PetscLayoutSetBlockSize(layout, 1);
4504: PetscLayoutSetLocalSize(layout, nroots);
4505: PetscLayoutSetUp(layout);
4506: PetscLayoutGetRanges(layout, &ranges);
4507: for (p = pStart; p < pEnd; ++p) {
4508: PetscInt gdof, gcdof;
4510: PetscSectionGetDof(globalSection, p, &gdof);
4511: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4512: if (gcdof > (gdof < 0 ? -(gdof+1) : gdof)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d has %d constraints > %d dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
4513: nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4514: }
4515: PetscMalloc1(nleaves, &local);
4516: PetscMalloc1(nleaves, &remote);
4517: for (p = pStart, l = 0; p < pEnd; ++p) {
4518: const PetscInt *cind;
4519: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
4521: PetscSectionGetDof(localSection, p, &dof);
4522: PetscSectionGetOffset(localSection, p, &off);
4523: PetscSectionGetConstraintDof(localSection, p, &cdof);
4524: PetscSectionGetConstraintIndices(localSection, p, &cind);
4525: PetscSectionGetDof(globalSection, p, &gdof);
4526: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4527: PetscSectionGetOffset(globalSection, p, &goff);
4528: if (!gdof) continue; /* Censored point */
4529: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4530: if (gsize != dof-cdof) {
4531: if (gsize != dof) SETERRQ4(comm, PETSC_ERR_ARG_WRONG, "Global dof %d for point %d is neither the constrained size %d, nor the unconstrained %d", gsize, p, dof-cdof, dof);
4532: cdof = 0; /* Ignore constraints */
4533: }
4534: for (d = 0, c = 0; d < dof; ++d) {
4535: if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4536: local[l+d-c] = off+d;
4537: }
4538: if (gdof < 0) {
4539: for (d = 0; d < gsize; ++d, ++l) {
4540: PetscInt offset = -(goff+1) + d, r;
4542: PetscFindInt(offset,size+1,ranges,&r);
4543: if (r < 0) r = -(r+2);
4544: if ((r < 0) || (r >= size)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d mapped to invalid process %d (%d, %d)", p, r, gdof, goff);
4545: remote[l].rank = r;
4546: remote[l].index = offset - ranges[r];
4547: }
4548: } else {
4549: for (d = 0; d < gsize; ++d, ++l) {
4550: remote[l].rank = rank;
4551: remote[l].index = goff+d - ranges[rank];
4552: }
4553: }
4554: }
4555: if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4556: PetscLayoutDestroy(&layout);
4557: PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4558: return(0);
4559: }
4561: /*@
4562: DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4564: Input Parameter:
4565: . dm - The DM
4567: Output Parameter:
4568: . sf - The PetscSF
4570: Level: intermediate
4572: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4574: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4575: @*/
4576: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4577: {
4581: *sf = dm->sf;
4582: return(0);
4583: }
4585: /*@
4586: DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4588: Input Parameters:
4589: + dm - The DM
4590: - sf - The PetscSF
4592: Level: intermediate
4594: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4595: @*/
4596: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4597: {
4603: PetscObjectReference((PetscObject) sf);
4604: PetscSFDestroy(&dm->sf);
4605: dm->sf = sf;
4606: return(0);
4607: }
4609: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4610: {
4611: PetscClassId id;
4615: PetscObjectGetClassId(disc, &id);
4616: if (id == PETSCFE_CLASSID) {
4617: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4618: } else if (id == PETSCFV_CLASSID) {
4619: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4620: } else {
4621: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4622: }
4623: return(0);
4624: }
4626: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4627: {
4628: RegionField *tmpr;
4629: PetscInt Nf = dm->Nf, f;
4633: if (Nf >= NfNew) return(0);
4634: PetscMalloc1(NfNew, &tmpr);
4635: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4636: for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4637: PetscFree(dm->fields);
4638: dm->Nf = NfNew;
4639: dm->fields = tmpr;
4640: return(0);
4641: }
4643: /*@
4644: DMClearFields - Remove all fields from the DM
4646: Logically collective on dm
4648: Input Parameter:
4649: . dm - The DM
4651: Level: intermediate
4653: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4654: @*/
4655: PetscErrorCode DMClearFields(DM dm)
4656: {
4657: PetscInt f;
4662: for (f = 0; f < dm->Nf; ++f) {
4663: PetscObjectDestroy(&dm->fields[f].disc);
4664: DMLabelDestroy(&dm->fields[f].label);
4665: }
4666: PetscFree(dm->fields);
4667: dm->fields = NULL;
4668: dm->Nf = 0;
4669: return(0);
4670: }
4672: /*@
4673: DMGetNumFields - Get the number of fields in the DM
4675: Not collective
4677: Input Parameter:
4678: . dm - The DM
4680: Output Parameter:
4681: . Nf - The number of fields
4683: Level: intermediate
4685: .seealso: DMSetNumFields(), DMSetField()
4686: @*/
4687: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4688: {
4692: *numFields = dm->Nf;
4693: return(0);
4694: }
4696: /*@
4697: DMSetNumFields - Set the number of fields in the DM
4699: Logically collective on dm
4701: Input Parameters:
4702: + dm - The DM
4703: - Nf - The number of fields
4705: Level: intermediate
4707: .seealso: DMGetNumFields(), DMSetField()
4708: @*/
4709: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4710: {
4711: PetscInt Nf, f;
4716: DMGetNumFields(dm, &Nf);
4717: for (f = Nf; f < numFields; ++f) {
4718: PetscContainer obj;
4720: PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4721: DMAddField(dm, NULL, (PetscObject) obj);
4722: PetscContainerDestroy(&obj);
4723: }
4724: return(0);
4725: }
4727: /*@
4728: DMGetField - Return the discretization object for a given DM field
4730: Not collective
4732: Input Parameters:
4733: + dm - The DM
4734: - f - The field number
4736: Output Parameters:
4737: + label - The label indicating the support of the field, or NULL for the entire mesh
4738: - field - The discretization object
4740: Level: intermediate
4742: .seealso: DMAddField(), DMSetField()
4743: @*/
4744: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4745: {
4749: 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);
4750: if (label) *label = dm->fields[f].label;
4751: if (field) *field = dm->fields[f].disc;
4752: return(0);
4753: }
4755: /* Does not clear the DS */
4756: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4757: {
4761: DMFieldEnlarge_Static(dm, f+1);
4762: DMLabelDestroy(&dm->fields[f].label);
4763: PetscObjectDestroy(&dm->fields[f].disc);
4764: dm->fields[f].label = label;
4765: dm->fields[f].disc = field;
4766: PetscObjectReference((PetscObject) label);
4767: PetscObjectReference((PetscObject) field);
4768: return(0);
4769: }
4771: /*@
4772: DMSetField - Set the discretization object for a given DM field
4774: Logically collective on dm
4776: Input Parameters:
4777: + dm - The DM
4778: . f - The field number
4779: . label - The label indicating the support of the field, or NULL for the entire mesh
4780: - field - The discretization object
4782: Level: intermediate
4784: .seealso: DMAddField(), DMGetField()
4785: @*/
4786: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4787: {
4794: if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4795: DMSetField_Internal(dm, f, label, field);
4796: DMSetDefaultAdjacency_Private(dm, f, field);
4797: DMClearDS(dm);
4798: return(0);
4799: }
4801: /*@
4802: DMAddField - Add the discretization object for the given DM field
4804: Logically collective on dm
4806: Input Parameters:
4807: + dm - The DM
4808: . label - The label indicating the support of the field, or NULL for the entire mesh
4809: - field - The discretization object
4811: Level: intermediate
4813: .seealso: DMSetField(), DMGetField()
4814: @*/
4815: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4816: {
4817: PetscInt Nf = dm->Nf;
4824: DMFieldEnlarge_Static(dm, Nf+1);
4825: dm->fields[Nf].label = label;
4826: dm->fields[Nf].disc = field;
4827: PetscObjectReference((PetscObject) label);
4828: PetscObjectReference((PetscObject) field);
4829: DMSetDefaultAdjacency_Private(dm, Nf, field);
4830: DMClearDS(dm);
4831: return(0);
4832: }
4834: /*@
4835: DMCopyFields - Copy the discretizations for the DM into another DM
4837: Collective on dm
4839: Input Parameter:
4840: . dm - The DM
4842: Output Parameter:
4843: . newdm - The DM
4845: Level: advanced
4847: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4848: @*/
4849: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4850: {
4851: PetscInt Nf, f;
4855: if (dm == newdm) return(0);
4856: DMGetNumFields(dm, &Nf);
4857: DMClearFields(newdm);
4858: for (f = 0; f < Nf; ++f) {
4859: DMLabel label;
4860: PetscObject field;
4861: PetscBool useCone, useClosure;
4863: DMGetField(dm, f, &label, &field);
4864: DMSetField(newdm, f, label, field);
4865: DMGetAdjacency(dm, f, &useCone, &useClosure);
4866: DMSetAdjacency(newdm, f, useCone, useClosure);
4867: }
4868: return(0);
4869: }
4871: /*@
4872: DMGetAdjacency - Returns the flags for determining variable influence
4874: Not collective
4876: Input Parameters:
4877: + dm - The DM object
4878: - f - The field number, or PETSC_DEFAULT for the default adjacency
4880: Output Parameter:
4881: + useCone - Flag for variable influence starting with the cone operation
4882: - useClosure - Flag for variable influence using transitive closure
4884: Notes:
4885: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4886: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4887: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4888: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4890: Level: developer
4892: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4893: @*/
4894: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4895: {
4900: if (f < 0) {
4901: if (useCone) *useCone = dm->adjacency[0];
4902: if (useClosure) *useClosure = dm->adjacency[1];
4903: } else {
4904: PetscInt Nf;
4907: DMGetNumFields(dm, &Nf);
4908: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4909: if (useCone) *useCone = dm->fields[f].adjacency[0];
4910: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4911: }
4912: return(0);
4913: }
4915: /*@
4916: DMSetAdjacency - Set the flags for determining variable influence
4918: Not collective
4920: Input Parameters:
4921: + dm - The DM object
4922: . f - The field number
4923: . useCone - Flag for variable influence starting with the cone operation
4924: - useClosure - Flag for variable influence using transitive closure
4926: Notes:
4927: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4928: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4929: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4930: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4932: Level: developer
4934: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4935: @*/
4936: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4937: {
4940: if (f < 0) {
4941: dm->adjacency[0] = useCone;
4942: dm->adjacency[1] = useClosure;
4943: } else {
4944: PetscInt Nf;
4947: DMGetNumFields(dm, &Nf);
4948: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4949: dm->fields[f].adjacency[0] = useCone;
4950: dm->fields[f].adjacency[1] = useClosure;
4951: }
4952: return(0);
4953: }
4955: /*@
4956: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4958: Not collective
4960: Input Parameters:
4961: . dm - The DM object
4963: Output Parameter:
4964: + useCone - Flag for variable influence starting with the cone operation
4965: - useClosure - Flag for variable influence using transitive closure
4967: Notes:
4968: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4969: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4970: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4972: Level: developer
4974: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4975: @*/
4976: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4977: {
4978: PetscInt Nf;
4985: DMGetNumFields(dm, &Nf);
4986: if (!Nf) {
4987: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4988: } else {
4989: DMGetAdjacency(dm, 0, useCone, useClosure);
4990: }
4991: return(0);
4992: }
4994: /*@
4995: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
4997: Not collective
4999: Input Parameters:
5000: + dm - The DM object
5001: . useCone - Flag for variable influence starting with the cone operation
5002: - useClosure - Flag for variable influence using transitive closure
5004: Notes:
5005: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5006: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5007: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5009: Level: developer
5011: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5012: @*/
5013: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5014: {
5015: PetscInt Nf;
5020: DMGetNumFields(dm, &Nf);
5021: if (!Nf) {
5022: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5023: } else {
5024: DMSetAdjacency(dm, 0, useCone, useClosure);
5025: }
5026: return(0);
5027: }
5029: /* Complete labels that are being used for FEM BC */
5030: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5031: {
5032: DMLabel label;
5033: PetscObject obj;
5034: PetscClassId id;
5035: PetscInt Nbd, bd;
5036: PetscBool isFE = PETSC_FALSE;
5037: PetscBool duplicate = PETSC_FALSE;
5041: DMGetField(dm, field, NULL, &obj);
5042: PetscObjectGetClassId(obj, &id);
5043: if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5044: DMGetLabel(dm, labelname, &label);
5045: if (isFE && label) {
5046: /* Only want to modify label once */
5047: PetscDSGetNumBoundary(ds, &Nbd);
5048: for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5049: const char *lname;
5051: PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5052: PetscStrcmp(lname, labelname, &duplicate);
5053: if (duplicate) break;
5054: }
5055: if (!duplicate) {
5056: DM plex;
5058: DMConvert(dm, DMPLEX, &plex);
5059: if (plex) {DMPlexLabelComplete(plex, label);}
5060: DMDestroy(&plex);
5061: }
5062: }
5063: return(0);
5064: }
5066: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5067: {
5068: DMSpace *tmpd;
5069: PetscInt Nds = dm->Nds, s;
5073: if (Nds >= NdsNew) return(0);
5074: PetscMalloc1(NdsNew, &tmpd);
5075: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5076: for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5077: PetscFree(dm->probs);
5078: dm->Nds = NdsNew;
5079: dm->probs = tmpd;
5080: return(0);
5081: }
5083: /*@
5084: DMGetNumDS - Get the number of discrete systems in the DM
5086: Not collective
5088: Input Parameter:
5089: . dm - The DM
5091: Output Parameter:
5092: . Nds - The number of PetscDS objects
5094: Level: intermediate
5096: .seealso: DMGetDS(), DMGetCellDS()
5097: @*/
5098: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5099: {
5103: *Nds = dm->Nds;
5104: return(0);
5105: }
5107: /*@
5108: DMClearDS - Remove all discrete systems from the DM
5110: Logically collective on dm
5112: Input Parameter:
5113: . dm - The DM
5115: Level: intermediate
5117: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5118: @*/
5119: PetscErrorCode DMClearDS(DM dm)
5120: {
5121: PetscInt s;
5126: for (s = 0; s < dm->Nds; ++s) {
5127: PetscDSDestroy(&dm->probs[s].ds);
5128: DMLabelDestroy(&dm->probs[s].label);
5129: ISDestroy(&dm->probs[s].fields);
5130: }
5131: PetscFree(dm->probs);
5132: dm->probs = NULL;
5133: dm->Nds = 0;
5134: return(0);
5135: }
5137: /*@
5138: DMGetDS - Get the default PetscDS
5140: Not collective
5142: Input Parameter:
5143: . dm - The DM
5145: Output Parameter:
5146: . prob - The default PetscDS
5148: Level: intermediate
5150: .seealso: DMGetCellDS(), DMGetRegionDS()
5151: @*/
5152: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5153: {
5159: if (dm->Nds <= 0) {
5160: PetscDS ds;
5162: PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5163: DMSetRegionDS(dm, NULL, NULL, ds);
5164: PetscDSDestroy(&ds);
5165: }
5166: *prob = dm->probs[0].ds;
5167: return(0);
5168: }
5170: /*@
5171: DMGetCellDS - Get the PetscDS defined on a given cell
5173: Not collective
5175: Input Parameters:
5176: + dm - The DM
5177: - point - Cell for the DS
5179: Output Parameter:
5180: . prob - The PetscDS defined on the given cell
5182: Level: developer
5184: .seealso: DMGetDS(), DMSetRegionDS()
5185: @*/
5186: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5187: {
5188: PetscDS probDef = NULL;
5189: PetscInt s;
5195: if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5196: *prob = NULL;
5197: for (s = 0; s < dm->Nds; ++s) {
5198: PetscInt val;
5200: if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5201: else {
5202: DMLabelGetValue(dm->probs[s].label, point, &val);
5203: if (val >= 0) {*prob = dm->probs[s].ds; break;}
5204: }
5205: }
5206: if (!*prob) *prob = probDef;
5207: return(0);
5208: }
5210: /*@
5211: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5213: Not collective
5215: Input Parameters:
5216: + dm - The DM
5217: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5219: Output Parameters:
5220: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5221: - prob - The PetscDS defined on the given region, or NULL
5223: Note: If the label is missing, this function returns an error
5225: Level: advanced
5227: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5228: @*/
5229: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5230: {
5231: PetscInt Nds = dm->Nds, s;
5238: for (s = 0; s < Nds; ++s) {
5239: if (dm->probs[s].label == label) {
5240: if (fields) *fields = dm->probs[s].fields;
5241: if (ds) *ds = dm->probs[s].ds;
5242: return(0);
5243: }
5244: }
5245: return(0);
5246: }
5248: /*@
5249: DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5251: Collective on dm
5253: Input Parameters:
5254: + dm - The DM
5255: . label - The DMLabel defining the mesh region, or NULL for the entire mesh
5256: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5257: - prob - The PetscDS defined on the given cell
5259: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5260: the fields argument is ignored.
5262: Level: advanced
5264: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5265: @*/
5266: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5267: {
5268: PetscInt Nds = dm->Nds, s;
5275: for (s = 0; s < Nds; ++s) {
5276: if (dm->probs[s].label == label) {
5277: PetscDSDestroy(&dm->probs[s].ds);
5278: dm->probs[s].ds = ds;
5279: return(0);
5280: }
5281: }
5282: DMDSEnlarge_Static(dm, Nds+1);
5283: PetscObjectReference((PetscObject) label);
5284: PetscObjectReference((PetscObject) fields);
5285: PetscObjectReference((PetscObject) ds);
5286: if (!label) {
5287: /* Put the NULL label at the front, so it is returned as the default */
5288: for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5289: Nds = 0;
5290: }
5291: dm->probs[Nds].label = label;
5292: dm->probs[Nds].fields = fields;
5293: dm->probs[Nds].ds = ds;
5294: return(0);
5295: }
5297: /*@
5298: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5300: Not collective
5302: Input Parameters:
5303: + dm - The DM
5304: - num - The region number, in [0, Nds)
5306: Output Parameters:
5307: + label - The region label, or NULL
5308: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5309: - ds - The PetscDS defined on the given region, or NULL
5311: Level: advanced
5313: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5314: @*/
5315: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5316: {
5317: PetscInt Nds;
5322: DMGetNumDS(dm, &Nds);
5323: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5324: if (label) {
5326: *label = dm->probs[num].label;
5327: }
5328: if (fields) {
5330: *fields = dm->probs[num].fields;
5331: }
5332: if (ds) {
5334: *ds = dm->probs[num].ds;
5335: }
5336: return(0);
5337: }
5339: /*@
5340: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5342: Not collective
5344: Input Parameters:
5345: + dm - The DM
5346: . num - The region number, in [0, Nds)
5347: . label - The region label, or NULL
5348: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5349: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5351: Level: advanced
5353: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5354: @*/
5355: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5356: {
5357: PetscInt Nds;
5363: DMGetNumDS(dm, &Nds);
5364: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5365: PetscObjectReference((PetscObject) label);
5366: DMLabelDestroy(&dm->probs[num].label);
5367: dm->probs[num].label = label;
5368: if (fields) {
5370: PetscObjectReference((PetscObject) fields);
5371: ISDestroy(&dm->probs[num].fields);
5372: dm->probs[num].fields = fields;
5373: }
5374: if (ds) {
5376: PetscObjectReference((PetscObject) ds);
5377: PetscDSDestroy(&dm->probs[num].ds);
5378: dm->probs[num].ds = ds;
5379: }
5380: return(0);
5381: }
5383: /*@
5384: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5386: Not collective
5388: Input Parameters:
5389: + dm - The DM
5390: - ds - The PetscDS defined on the given region
5392: Output Parameter:
5393: . num - The region number, in [0, Nds), or -1 if not found
5395: Level: advanced
5397: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5398: @*/
5399: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5400: {
5401: PetscInt Nds, n;
5408: DMGetNumDS(dm, &Nds);
5409: for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5410: if (n >= Nds) *num = -1;
5411: else *num = n;
5412: return(0);
5413: }
5415: /*@
5416: DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5418: Collective on dm
5420: Input Parameter:
5421: . dm - The DM
5423: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5425: Level: intermediate
5427: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5428: @*/
5429: PetscErrorCode DMCreateDS(DM dm)
5430: {
5431: MPI_Comm comm;
5432: PetscDS dsDef;
5433: DMLabel *labelSet;
5434: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5435: PetscBool doSetup = PETSC_TRUE;
5440: if (!dm->fields) return(0);
5441: PetscObjectGetComm((PetscObject) dm, &comm);
5442: DMGetCoordinateDim(dm, &dE);
5443: /* Determine how many regions we have */
5444: PetscMalloc1(Nf, &labelSet);
5445: Nl = 0;
5446: Ndef = 0;
5447: for (f = 0; f < Nf; ++f) {
5448: DMLabel label = dm->fields[f].label;
5449: PetscInt l;
5451: if (!label) {++Ndef; continue;}
5452: for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5453: if (l < Nl) continue;
5454: labelSet[Nl++] = label;
5455: }
5456: /* Create default DS if there are no labels to intersect with */
5457: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5458: if (!dsDef && Ndef && !Nl) {
5459: IS fields;
5460: PetscInt *fld, nf;
5462: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5463: if (nf) {
5464: PetscMalloc1(nf, &fld);
5465: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5466: ISCreate(PETSC_COMM_SELF, &fields);
5467: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5468: ISSetType(fields, ISGENERAL);
5469: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5471: PetscDSCreate(comm, &dsDef);
5472: DMSetRegionDS(dm, NULL, fields, dsDef);
5473: PetscDSDestroy(&dsDef);
5474: ISDestroy(&fields);
5475: }
5476: }
5477: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5478: if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5479: /* Intersect labels with default fields */
5480: if (Ndef && Nl) {
5481: DM plex;
5482: DMLabel cellLabel;
5483: IS fieldIS, allcellIS, defcellIS = NULL;
5484: PetscInt *fields;
5485: const PetscInt *cells;
5486: PetscInt depth, nf = 0, n, c;
5488: DMConvert(dm, DMPLEX, &plex);
5489: DMPlexGetDepth(plex, &depth);
5490: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5491: if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5492: for (l = 0; l < Nl; ++l) {
5493: DMLabel label = labelSet[l];
5494: IS pointIS;
5496: ISDestroy(&defcellIS);
5497: DMLabelGetStratumIS(label, 1, &pointIS);
5498: ISDifference(allcellIS, pointIS, &defcellIS);
5499: ISDestroy(&pointIS);
5500: }
5501: ISDestroy(&allcellIS);
5503: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5504: ISGetLocalSize(defcellIS, &n);
5505: ISGetIndices(defcellIS, &cells);
5506: for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5507: ISRestoreIndices(defcellIS, &cells);
5508: ISDestroy(&defcellIS);
5509: DMPlexLabelComplete(plex, cellLabel);
5511: PetscMalloc1(Ndef, &fields);
5512: for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5513: ISCreate(PETSC_COMM_SELF, &fieldIS);
5514: PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5515: ISSetType(fieldIS, ISGENERAL);
5516: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5518: PetscDSCreate(comm, &dsDef);
5519: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5520: DMLabelDestroy(&cellLabel);
5521: PetscDSSetCoordinateDimension(dsDef, dE);
5522: PetscDSDestroy(&dsDef);
5523: ISDestroy(&fieldIS);
5524: DMDestroy(&plex);
5525: }
5526: /* Create label DSes
5527: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5528: */
5529: /* TODO Should check that labels are disjoint */
5530: for (l = 0; l < Nl; ++l) {
5531: DMLabel label = labelSet[l];
5532: PetscDS ds;
5533: IS fields;
5534: PetscInt *fld, nf;
5536: PetscDSCreate(comm, &ds);
5537: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5538: PetscMalloc1(nf, &fld);
5539: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5540: ISCreate(PETSC_COMM_SELF, &fields);
5541: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5542: ISSetType(fields, ISGENERAL);
5543: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5544: DMSetRegionDS(dm, label, fields, ds);
5545: ISDestroy(&fields);
5546: PetscDSSetCoordinateDimension(ds, dE);
5547: {
5548: DMPolytopeType ct;
5549: PetscInt lStart, lEnd;
5550: PetscBool isHybridLocal = PETSC_FALSE, isHybrid;
5552: DMLabelGetBounds(label, &lStart, &lEnd);
5553: if (lStart >= 0) {
5554: DMPlexGetCellType(dm, lStart, &ct);
5555: switch (ct) {
5556: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5557: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5558: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5559: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5560: isHybridLocal = PETSC_TRUE;break;
5561: default: break;
5562: }
5563: }
5564: MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5565: PetscDSSetHybrid(ds, isHybrid);
5566: }
5567: PetscDSDestroy(&ds);
5568: }
5569: PetscFree(labelSet);
5570: /* Set fields in DSes */
5571: for (s = 0; s < dm->Nds; ++s) {
5572: PetscDS ds = dm->probs[s].ds;
5573: IS fields = dm->probs[s].fields;
5574: const PetscInt *fld;
5575: PetscInt nf;
5577: ISGetLocalSize(fields, &nf);
5578: ISGetIndices(fields, &fld);
5579: for (f = 0; f < nf; ++f) {
5580: PetscObject disc = dm->fields[fld[f]].disc;
5581: PetscBool isHybrid;
5582: PetscClassId id;
5584: PetscDSGetHybrid(ds, &isHybrid);
5585: /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5586: if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5587: PetscDSSetDiscretization(ds, f, disc);
5588: /* We allow people to have placeholder fields and construct the Section by hand */
5589: PetscObjectGetClassId(disc, &id);
5590: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5591: }
5592: ISRestoreIndices(fields, &fld);
5593: }
5594: /* Setup DSes */
5595: if (doSetup) {
5596: for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5597: }
5598: return(0);
5599: }
5601: /*@
5602: DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5604: Collective on DM
5606: Input Parameters:
5607: + dm - The DM
5608: - time - The time
5610: Output Parameters:
5611: + u - The vector will be filled with exact solution values, or NULL
5612: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5614: Note: The user must call PetscDSSetExactSolution() beforehand
5616: Level: developer
5618: .seealso: PetscDSSetExactSolution()
5619: @*/
5620: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5621: {
5622: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5623: void **ectxs;
5624: PetscInt Nf, Nds, s;
5625: PetscErrorCode ierr;
5631: DMGetNumFields(dm, &Nf);
5632: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5633: DMGetNumDS(dm, &Nds);
5634: for (s = 0; s < Nds; ++s) {
5635: PetscDS ds;
5636: DMLabel label;
5637: IS fieldIS;
5638: const PetscInt *fields, id = 1;
5639: PetscInt dsNf, f;
5641: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5642: PetscDSGetNumFields(ds, &dsNf);
5643: ISGetIndices(fieldIS, &fields);
5644: PetscArrayzero(exacts, Nf);
5645: PetscArrayzero(ectxs, Nf);
5646: if (u) {
5647: for (f = 0; f < dsNf; ++f) {
5648: const PetscInt field = fields[f];
5649: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5650: }
5651: ISRestoreIndices(fieldIS, &fields);
5652: if (label) {
5653: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5654: } else {
5655: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5656: }
5657: }
5658: if (u_t) {
5659: PetscArrayzero(exacts, Nf);
5660: PetscArrayzero(ectxs, Nf);
5661: for (f = 0; f < dsNf; ++f) {
5662: const PetscInt field = fields[f];
5663: PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5664: }
5665: ISRestoreIndices(fieldIS, &fields);
5666: if (label) {
5667: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5668: } else {
5669: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5670: }
5671: }
5672: }
5673: if (u) {
5674: PetscObjectSetName((PetscObject) u, "Exact Solution");
5675: PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5676: }
5677: if (u_t) {
5678: PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5679: PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5680: }
5681: PetscFree2(exacts, ectxs);
5682: return(0);
5683: }
5685: /*@
5686: DMCopyDS - Copy the discrete systems for the DM into another DM
5688: Collective on dm
5690: Input Parameter:
5691: . dm - The DM
5693: Output Parameter:
5694: . newdm - The DM
5696: Level: advanced
5698: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5699: @*/
5700: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5701: {
5702: PetscInt Nds, s;
5706: if (dm == newdm) return(0);
5707: DMGetNumDS(dm, &Nds);
5708: DMClearDS(newdm);
5709: for (s = 0; s < Nds; ++s) {
5710: DMLabel label;
5711: IS fields;
5712: PetscDS ds;
5713: PetscInt Nbd, bd;
5715: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5716: DMSetRegionDS(newdm, label, fields, ds);
5717: PetscDSGetNumBoundary(ds, &Nbd);
5718: for (bd = 0; bd < Nbd; ++bd) {
5719: const char *labelname, *name;
5720: PetscInt field;
5722: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5723: PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5724: DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5725: }
5726: }
5727: return(0);
5728: }
5730: /*@
5731: DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5733: Collective on dm
5735: Input Parameter:
5736: . dm - The DM
5738: Output Parameter:
5739: . newdm - The DM
5741: Level: advanced
5743: .seealso: DMCopyFields(), DMCopyDS()
5744: @*/
5745: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5746: {
5750: DMCopyFields(dm, newdm);
5751: DMCopyDS(dm, newdm);
5752: return(0);
5753: }
5755: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5756: {
5757: DM dm_coord,dmc_coord;
5759: Vec coords,ccoords;
5760: Mat inject;
5762: DMGetCoordinateDM(dm,&dm_coord);
5763: DMGetCoordinateDM(dmc,&dmc_coord);
5764: DMGetCoordinates(dm,&coords);
5765: DMGetCoordinates(dmc,&ccoords);
5766: if (coords && !ccoords) {
5767: DMCreateGlobalVector(dmc_coord,&ccoords);
5768: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5769: DMCreateInjection(dmc_coord,dm_coord,&inject);
5770: MatRestrict(inject,coords,ccoords);
5771: MatDestroy(&inject);
5772: DMSetCoordinates(dmc,ccoords);
5773: VecDestroy(&ccoords);
5774: }
5775: return(0);
5776: }
5778: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5779: {
5780: DM dm_coord,subdm_coord;
5782: Vec coords,ccoords,clcoords;
5783: VecScatter *scat_i,*scat_g;
5785: DMGetCoordinateDM(dm,&dm_coord);
5786: DMGetCoordinateDM(subdm,&subdm_coord);
5787: DMGetCoordinates(dm,&coords);
5788: DMGetCoordinates(subdm,&ccoords);
5789: if (coords && !ccoords) {
5790: DMCreateGlobalVector(subdm_coord,&ccoords);
5791: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5792: DMCreateLocalVector(subdm_coord,&clcoords);
5793: PetscObjectSetName((PetscObject)clcoords,"coordinates");
5794: DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5795: VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5796: VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5797: VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5798: VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5799: DMSetCoordinates(subdm,ccoords);
5800: DMSetCoordinatesLocal(subdm,clcoords);
5801: VecScatterDestroy(&scat_i[0]);
5802: VecScatterDestroy(&scat_g[0]);
5803: VecDestroy(&ccoords);
5804: VecDestroy(&clcoords);
5805: PetscFree(scat_i);
5806: PetscFree(scat_g);
5807: }
5808: return(0);
5809: }
5811: /*@
5812: DMGetDimension - Return the topological dimension of the DM
5814: Not collective
5816: Input Parameter:
5817: . dm - The DM
5819: Output Parameter:
5820: . dim - The topological dimension
5822: Level: beginner
5824: .seealso: DMSetDimension(), DMCreate()
5825: @*/
5826: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5827: {
5831: *dim = dm->dim;
5832: return(0);
5833: }
5835: /*@
5836: DMSetDimension - Set the topological dimension of the DM
5838: Collective on dm
5840: Input Parameters:
5841: + dm - The DM
5842: - dim - The topological dimension
5844: Level: beginner
5846: .seealso: DMGetDimension(), DMCreate()
5847: @*/
5848: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5849: {
5850: PetscDS ds;
5856: dm->dim = dim;
5857: DMGetDS(dm, &ds);
5858: if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5859: return(0);
5860: }
5862: /*@
5863: DMGetDimPoints - Get the half-open interval for all points of a given dimension
5865: Collective on dm
5867: Input Parameters:
5868: + dm - the DM
5869: - dim - the dimension
5871: Output Parameters:
5872: + pStart - The first point of the given dimension
5873: - pEnd - The first point following points of the given dimension
5875: Note:
5876: The points are vertices in the Hasse diagram encoding the topology. This is explained in
5877: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5878: then the interval is empty.
5880: Level: intermediate
5882: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5883: @*/
5884: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5885: {
5886: PetscInt d;
5891: DMGetDimension(dm, &d);
5892: if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5893: if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5894: (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5895: return(0);
5896: }
5898: /*@
5899: DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5901: Collective on dm
5903: Input Parameters:
5904: + dm - the DM
5905: - c - coordinate vector
5907: Notes:
5908: The coordinates do include those for ghost points, which are in the local vector.
5910: The vector c should be destroyed by the caller.
5912: Level: intermediate
5914: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5915: @*/
5916: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5917: {
5923: PetscObjectReference((PetscObject) c);
5924: VecDestroy(&dm->coordinates);
5925: dm->coordinates = c;
5926: VecDestroy(&dm->coordinatesLocal);
5927: DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5928: DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5929: return(0);
5930: }
5932: /*@
5933: DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5935: Not collective
5937: Input Parameters:
5938: + dm - the DM
5939: - c - coordinate vector
5941: Notes:
5942: The coordinates of ghost points can be set using DMSetCoordinates()
5943: followed by DMGetCoordinatesLocal(). This is intended to enable the
5944: setting of ghost coordinates outside of the domain.
5946: The vector c should be destroyed by the caller.
5948: Level: intermediate
5950: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5951: @*/
5952: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5953: {
5959: PetscObjectReference((PetscObject) c);
5960: VecDestroy(&dm->coordinatesLocal);
5962: dm->coordinatesLocal = c;
5964: VecDestroy(&dm->coordinates);
5965: return(0);
5966: }
5968: /*@
5969: DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5971: Collective on dm
5973: Input Parameter:
5974: . dm - the DM
5976: Output Parameter:
5977: . c - global coordinate vector
5979: Note:
5980: This is a borrowed reference, so the user should NOT destroy this vector
5982: Each process has only the local coordinates (does NOT have the ghost coordinates).
5984: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5985: and (x_0,y_0,z_0,x_1,y_1,z_1...)
5987: Level: intermediate
5989: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5990: @*/
5991: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5992: {
5998: if (!dm->coordinates && dm->coordinatesLocal) {
5999: DM cdm = NULL;
6000: PetscBool localized;
6002: DMGetCoordinateDM(dm, &cdm);
6003: DMCreateGlobalVector(cdm, &dm->coordinates);
6004: DMGetCoordinatesLocalized(dm, &localized);
6005: /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6006: if (localized) {
6007: PetscInt cdim;
6009: DMGetCoordinateDim(dm, &cdim);
6010: VecSetBlockSize(dm->coordinates, cdim);
6011: }
6012: PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6013: DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6014: DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6015: }
6016: *c = dm->coordinates;
6017: return(0);
6018: }
6020: /*@
6021: DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6023: Collective on dm
6025: Input Parameter:
6026: . dm - the DM
6028: Level: advanced
6030: .seealso: DMGetCoordinatesLocalNoncollective()
6031: @*/
6032: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6033: {
6038: if (!dm->coordinatesLocal && dm->coordinates) {
6039: DM cdm = NULL;
6040: PetscBool localized;
6042: DMGetCoordinateDM(dm, &cdm);
6043: DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6044: DMGetCoordinatesLocalized(dm, &localized);
6045: /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6046: if (localized) {
6047: PetscInt cdim;
6049: DMGetCoordinateDim(dm, &cdim);
6050: VecSetBlockSize(dm->coordinates, cdim);
6051: }
6052: PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6053: DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6054: DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6055: }
6056: return(0);
6057: }
6059: /*@
6060: DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6062: Collective on dm
6064: Input Parameter:
6065: . dm - the DM
6067: Output Parameter:
6068: . c - coordinate vector
6070: Note:
6071: This is a borrowed reference, so the user should NOT destroy this vector
6073: Each process has the local and ghost coordinates
6075: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6076: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6078: Level: intermediate
6080: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6081: @*/
6082: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6083: {
6089: DMGetCoordinatesLocalSetUp(dm);
6090: *c = dm->coordinatesLocal;
6091: return(0);
6092: }
6094: /*@
6095: DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6097: Not collective
6099: Input Parameter:
6100: . dm - the DM
6102: Output Parameter:
6103: . c - coordinate vector
6105: Level: advanced
6107: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6108: @*/
6109: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6110: {
6114: if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6115: *c = dm->coordinatesLocal;
6116: return(0);
6117: }
6119: /*@
6120: DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6122: Not collective
6124: Input Parameter:
6125: + dm - the DM
6126: - p - the IS of points whose coordinates will be returned
6128: Output Parameter:
6129: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6130: - pCoord - the Vec with coordinates of points in p
6132: Note:
6133: DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6135: This creates a new vector, so the user SHOULD destroy this vector
6137: Each process has the local and ghost coordinates
6139: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6140: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6142: Level: advanced
6144: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6145: @*/
6146: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6147: {
6148: PetscSection cs, newcs;
6149: Vec coords;
6150: const PetscScalar *arr;
6151: PetscScalar *newarr=NULL;
6152: PetscInt n;
6153: PetscErrorCode ierr;
6160: if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6161: if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6162: cs = dm->coordinateDM->localSection;
6163: coords = dm->coordinatesLocal;
6164: VecGetArrayRead(coords, &arr);
6165: PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6166: VecRestoreArrayRead(coords, &arr);
6167: if (pCoord) {
6168: PetscSectionGetStorageSize(newcs, &n);
6169: /* set array in two steps to mimic PETSC_OWN_POINTER */
6170: VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6171: VecReplaceArray(*pCoord, newarr);
6172: } else {
6173: PetscFree(newarr);
6174: }
6175: if (pCoordSection) {*pCoordSection = newcs;}
6176: else {PetscSectionDestroy(&newcs);}
6177: return(0);
6178: }
6180: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6181: {
6187: if (!dm->coordinateField) {
6188: if (dm->ops->createcoordinatefield) {
6189: (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6190: }
6191: }
6192: *field = dm->coordinateField;
6193: return(0);
6194: }
6196: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6197: {
6203: PetscObjectReference((PetscObject)field);
6204: DMFieldDestroy(&dm->coordinateField);
6205: dm->coordinateField = field;
6206: return(0);
6207: }
6209: /*@
6210: DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6212: Collective on dm
6214: Input Parameter:
6215: . dm - the DM
6217: Output Parameter:
6218: . cdm - coordinate DM
6220: Level: intermediate
6222: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6223: @*/
6224: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6225: {
6231: if (!dm->coordinateDM) {
6232: DM cdm;
6234: if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6235: (*dm->ops->createcoordinatedm)(dm, &cdm);
6236: /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6237: * until the call to CreateCoordinateDM) */
6238: DMDestroy(&dm->coordinateDM);
6239: dm->coordinateDM = cdm;
6240: }
6241: *cdm = dm->coordinateDM;
6242: return(0);
6243: }
6245: /*@
6246: DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6248: Logically Collective on dm
6250: Input Parameters:
6251: + dm - the DM
6252: - cdm - coordinate DM
6254: Level: intermediate
6256: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6257: @*/
6258: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6259: {
6265: PetscObjectReference((PetscObject)cdm);
6266: DMDestroy(&dm->coordinateDM);
6267: dm->coordinateDM = cdm;
6268: return(0);
6269: }
6271: /*@
6272: DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6274: Not Collective
6276: Input Parameter:
6277: . dm - The DM object
6279: Output Parameter:
6280: . dim - The embedding dimension
6282: Level: intermediate
6284: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6285: @*/
6286: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6287: {
6291: if (dm->dimEmbed == PETSC_DEFAULT) {
6292: dm->dimEmbed = dm->dim;
6293: }
6294: *dim = dm->dimEmbed;
6295: return(0);
6296: }
6298: /*@
6299: DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6301: Not Collective
6303: Input Parameters:
6304: + dm - The DM object
6305: - dim - The embedding dimension
6307: Level: intermediate
6309: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6310: @*/
6311: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6312: {
6313: PetscDS ds;
6318: dm->dimEmbed = dim;
6319: DMGetDS(dm, &ds);
6320: PetscDSSetCoordinateDimension(ds, dim);
6321: return(0);
6322: }
6324: /*@
6325: DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6327: Collective on dm
6329: Input Parameter:
6330: . dm - The DM object
6332: Output Parameter:
6333: . section - The PetscSection object
6335: Level: intermediate
6337: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6338: @*/
6339: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6340: {
6341: DM cdm;
6347: DMGetCoordinateDM(dm, &cdm);
6348: DMGetLocalSection(cdm, section);
6349: return(0);
6350: }
6352: /*@
6353: DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6355: Not Collective
6357: Input Parameters:
6358: + dm - The DM object
6359: . dim - The embedding dimension, or PETSC_DETERMINE
6360: - section - The PetscSection object
6362: Level: intermediate
6364: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6365: @*/
6366: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6367: {
6368: DM cdm;
6374: DMGetCoordinateDM(dm, &cdm);
6375: DMSetLocalSection(cdm, section);
6376: if (dim == PETSC_DETERMINE) {
6377: PetscInt d = PETSC_DEFAULT;
6378: PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6380: PetscSectionGetChart(section, &pStart, &pEnd);
6381: DMGetDimPoints(dm, 0, &vStart, &vEnd);
6382: pStart = PetscMax(vStart, pStart);
6383: pEnd = PetscMin(vEnd, pEnd);
6384: for (v = pStart; v < pEnd; ++v) {
6385: PetscSectionGetDof(section, v, &dd);
6386: if (dd) {d = dd; break;}
6387: }
6388: if (d >= 0) {DMSetCoordinateDim(dm, d);}
6389: }
6390: return(0);
6391: }
6393: /*@
6394: DMProjectCoordinates - Project coordinates to a different space
6396: Input Parameters:
6397: + dm - The DM object
6398: - disc - The new coordinate discretization
6400: Level: intermediate
6402: .seealso: DMGetCoordinateField()
6403: @*/
6404: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6405: {
6406: PetscObject discOld;
6407: PetscClassId classid;
6408: DM cdmOld,cdmNew;
6409: Vec coordsOld,coordsNew;
6410: Mat matInterp;
6417: DMGetCoordinateDM(dm, &cdmOld);
6418: /* Check current discretization is compatible */
6419: DMGetField(cdmOld, 0, NULL, &discOld);
6420: PetscObjectGetClassId(discOld, &classid);
6421: if (classid != PETSCFE_CLASSID) SETERRQ(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type not supported");
6422: /* Make a fresh clone of the coordinate DM */
6423: DMClone(cdmOld, &cdmNew);
6424: DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6425: DMCreateDS(cdmNew);
6426: /* Project the coordinate vector from old to new space */
6427: DMGetCoordinates(dm, &coordsOld);
6428: DMCreateGlobalVector(cdmNew, &coordsNew);
6429: DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6430: MatInterpolate(matInterp, coordsOld, coordsNew);
6431: MatDestroy(&matInterp);
6432: /* Set new coordinate structures */
6433: DMSetCoordinateField(dm, NULL);
6434: DMSetCoordinateDM(dm, cdmNew);
6435: DMSetCoordinates(dm, coordsNew);
6436: VecDestroy(&coordsNew);
6437: DMDestroy(&cdmNew);
6438: return(0);
6439: }
6441: /*@C
6442: DMGetPeriodicity - Get the description of mesh periodicity
6444: Input Parameters:
6445: . dm - The DM object
6447: Output Parameters:
6448: + per - Whether the DM is periodic or not
6449: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6450: . L - If we assume the mesh is a torus, this is the length of each coordinate
6451: - bd - This describes the type of periodicity in each topological dimension
6453: Level: developer
6455: .seealso: DMGetPeriodicity()
6456: @*/
6457: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6458: {
6461: if (per) *per = dm->periodic;
6462: if (L) *L = dm->L;
6463: if (maxCell) *maxCell = dm->maxCell;
6464: if (bd) *bd = dm->bdtype;
6465: return(0);
6466: }
6468: /*@C
6469: DMSetPeriodicity - Set the description of mesh periodicity
6471: Input Parameters:
6472: + dm - The DM object
6473: . per - Whether the DM is periodic or not.
6474: . 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.
6475: . L - If we assume the mesh is a torus, this is the length of each coordinate
6476: - bd - This describes the type of periodicity in each topological dimension
6478: 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.
6480: Level: developer
6482: .seealso: DMGetPeriodicity()
6483: @*/
6484: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6485: {
6486: PetscInt dim, d;
6495: DMGetDimension(dm, &dim);
6496: if (maxCell) {
6497: if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6498: for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6499: } else { /* remove maxCell information to disable automatic computation of localized vertices */
6500: PetscFree(dm->maxCell);
6501: }
6503: if (L) {
6504: if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6505: for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6506: }
6507: if (bd) {
6508: if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6509: for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6510: }
6511: dm->periodic = per;
6512: return(0);
6513: }
6515: /*@
6516: 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.
6518: Input Parameters:
6519: + dm - The DM
6520: . in - The input coordinate point (dim numbers)
6521: - endpoint - Include the endpoint L_i
6523: Output Parameter:
6524: . out - The localized coordinate point
6526: Level: developer
6528: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6529: @*/
6530: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6531: {
6532: PetscInt dim, d;
6536: DMGetCoordinateDim(dm, &dim);
6537: if (!dm->maxCell) {
6538: for (d = 0; d < dim; ++d) out[d] = in[d];
6539: } else {
6540: if (endpoint) {
6541: for (d = 0; d < dim; ++d) {
6542: 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)) {
6543: out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6544: } else {
6545: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6546: }
6547: }
6548: } else {
6549: for (d = 0; d < dim; ++d) {
6550: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6551: }
6552: }
6553: }
6554: return(0);
6555: }
6557: /*
6558: 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.
6560: Input Parameters:
6561: + dm - The DM
6562: . dim - The spatial dimension
6563: . anchor - The anchor point, the input point can be no more than maxCell away from it
6564: - in - The input coordinate point (dim numbers)
6566: Output Parameter:
6567: . out - The localized coordinate point
6569: Level: developer
6571: 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
6573: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6574: */
6575: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6576: {
6577: PetscInt d;
6580: if (!dm->maxCell) {
6581: for (d = 0; d < dim; ++d) out[d] = in[d];
6582: } else {
6583: for (d = 0; d < dim; ++d) {
6584: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6585: out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6586: } else {
6587: out[d] = in[d];
6588: }
6589: }
6590: }
6591: return(0);
6592: }
6594: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6595: {
6596: PetscInt d;
6599: if (!dm->maxCell) {
6600: for (d = 0; d < dim; ++d) out[d] = in[d];
6601: } else {
6602: for (d = 0; d < dim; ++d) {
6603: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6604: out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6605: } else {
6606: out[d] = in[d];
6607: }
6608: }
6609: }
6610: return(0);
6611: }
6613: /*
6614: 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.
6616: Input Parameters:
6617: + dm - The DM
6618: . dim - The spatial dimension
6619: . anchor - The anchor point, the input point can be no more than maxCell away from it
6620: . in - The input coordinate delta (dim numbers)
6621: - out - The input coordinate point (dim numbers)
6623: Output Parameter:
6624: . out - The localized coordinate in + out
6626: Level: developer
6628: 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
6630: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6631: */
6632: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6633: {
6634: PetscInt d;
6637: if (!dm->maxCell) {
6638: for (d = 0; d < dim; ++d) out[d] += in[d];
6639: } else {
6640: for (d = 0; d < dim; ++d) {
6641: const PetscReal maxC = dm->maxCell[d];
6643: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6644: const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6646: if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6647: 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]));
6648: out[d] += newCoord;
6649: } else {
6650: out[d] += in[d];
6651: }
6652: }
6653: }
6654: return(0);
6655: }
6657: /*@
6658: DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6660: Not collective
6662: Input Parameter:
6663: . dm - The DM
6665: Output Parameter:
6666: areLocalized - True if localized
6668: Level: developer
6670: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6671: @*/
6672: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6673: {
6674: DM cdm;
6675: PetscSection coordSection;
6676: PetscInt cStart, cEnd, sStart, sEnd, c, dof;
6677: PetscBool isPlex, alreadyLocalized;
6683: *areLocalized = PETSC_FALSE;
6685: /* We need some generic way of refering to cells/vertices */
6686: DMGetCoordinateDM(dm, &cdm);
6687: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6688: if (!isPlex) return(0);
6690: DMGetCoordinateSection(dm, &coordSection);
6691: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6692: PetscSectionGetChart(coordSection, &sStart, &sEnd);
6693: alreadyLocalized = PETSC_FALSE;
6694: for (c = cStart; c < cEnd; ++c) {
6695: if (c < sStart || c >= sEnd) continue;
6696: PetscSectionGetDof(coordSection, c, &dof);
6697: if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6698: }
6699: *areLocalized = alreadyLocalized;
6700: return(0);
6701: }
6703: /*@
6704: DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6706: Collective on dm
6708: Input Parameter:
6709: . dm - The DM
6711: Output Parameter:
6712: areLocalized - True if localized
6714: Level: developer
6716: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6717: @*/
6718: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6719: {
6720: PetscBool localized;
6726: DMGetCoordinatesLocalizedLocal(dm,&localized);
6727: MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6728: return(0);
6729: }
6731: /*@
6732: DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6734: Collective on dm
6736: Input Parameter:
6737: . dm - The DM
6739: Level: developer
6741: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6742: @*/
6743: PetscErrorCode DMLocalizeCoordinates(DM dm)
6744: {
6745: DM cdm;
6746: PetscSection coordSection, cSection;
6747: Vec coordinates, cVec;
6748: PetscScalar *coords, *coords2, *anchor, *localized;
6749: PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6750: PetscBool alreadyLocalized, alreadyLocalizedGlobal;
6751: PetscInt maxHeight = 0, h;
6752: PetscInt *pStart = NULL, *pEnd = NULL;
6757: if (!dm->periodic) return(0);
6758: DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6759: if (alreadyLocalized) return(0);
6761: /* We need some generic way of refering to cells/vertices */
6762: DMGetCoordinateDM(dm, &cdm);
6763: {
6764: PetscBool isplex;
6766: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6767: if (isplex) {
6768: DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6769: DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6770: DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6771: pEnd = &pStart[maxHeight + 1];
6772: newStart = vStart;
6773: newEnd = vEnd;
6774: for (h = 0; h <= maxHeight; h++) {
6775: DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6776: newStart = PetscMin(newStart,pStart[h]);
6777: newEnd = PetscMax(newEnd,pEnd[h]);
6778: }
6779: } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6780: }
6781: DMGetCoordinatesLocal(dm, &coordinates);
6782: if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6783: DMGetCoordinateSection(dm, &coordSection);
6784: VecGetBlockSize(coordinates, &bs);
6785: PetscSectionGetChart(coordSection,&sStart,&sEnd);
6787: PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6788: PetscSectionSetNumFields(cSection, 1);
6789: PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6790: PetscSectionSetFieldComponents(cSection, 0, Nc);
6791: PetscSectionSetChart(cSection, newStart, newEnd);
6793: DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6794: localized = &anchor[bs];
6795: alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6796: for (h = 0; h <= maxHeight; h++) {
6797: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6799: for (c = cStart; c < cEnd; ++c) {
6800: PetscScalar *cellCoords = NULL;
6801: PetscInt b;
6803: if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6804: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6805: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6806: for (d = 0; d < dof/bs; ++d) {
6807: DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6808: for (b = 0; b < bs; b++) {
6809: if (cellCoords[d*bs + b] != localized[b]) break;
6810: }
6811: if (b < bs) break;
6812: }
6813: if (d < dof/bs) {
6814: if (c >= sStart && c < sEnd) {
6815: PetscInt cdof;
6817: PetscSectionGetDof(coordSection, c, &cdof);
6818: if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6819: }
6820: PetscSectionSetDof(cSection, c, dof);
6821: PetscSectionSetFieldDof(cSection, c, 0, dof);
6822: }
6823: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6824: }
6825: }
6826: MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6827: if (alreadyLocalizedGlobal) {
6828: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6829: PetscSectionDestroy(&cSection);
6830: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6831: return(0);
6832: }
6833: for (v = vStart; v < vEnd; ++v) {
6834: PetscSectionGetDof(coordSection, v, &dof);
6835: PetscSectionSetDof(cSection, v, dof);
6836: PetscSectionSetFieldDof(cSection, v, 0, dof);
6837: }
6838: PetscSectionSetUp(cSection);
6839: PetscSectionGetStorageSize(cSection, &coordSize);
6840: VecCreate(PETSC_COMM_SELF, &cVec);
6841: PetscObjectSetName((PetscObject)cVec,"coordinates");
6842: VecSetBlockSize(cVec, bs);
6843: VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6844: VecSetType(cVec, VECSTANDARD);
6845: VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6846: VecGetArray(cVec, &coords2);
6847: for (v = vStart; v < vEnd; ++v) {
6848: PetscSectionGetDof(coordSection, v, &dof);
6849: PetscSectionGetOffset(coordSection, v, &off);
6850: PetscSectionGetOffset(cSection, v, &off2);
6851: for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6852: }
6853: for (h = 0; h <= maxHeight; h++) {
6854: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6856: for (c = cStart; c < cEnd; ++c) {
6857: PetscScalar *cellCoords = NULL;
6858: PetscInt b, cdof;
6860: PetscSectionGetDof(cSection,c,&cdof);
6861: if (!cdof) continue;
6862: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6863: PetscSectionGetOffset(cSection, c, &off2);
6864: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6865: for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6866: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6867: }
6868: }
6869: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6870: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6871: VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6872: VecRestoreArray(cVec, &coords2);
6873: DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6874: DMSetCoordinatesLocal(dm, cVec);
6875: VecDestroy(&cVec);
6876: PetscSectionDestroy(&cSection);
6877: return(0);
6878: }
6880: /*@
6881: DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6883: Collective on v (see explanation below)
6885: Input Parameters:
6886: + dm - The DM
6887: . v - The Vec of points
6888: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6889: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6891: Output Parameter:
6892: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6893: - cells - The PetscSF containing the ranks and local indices of the containing points.
6896: Level: developer
6898: Notes:
6899: To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6900: To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6902: If *cellSF is NULL on input, a PetscSF will be created.
6903: If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6905: An array that maps each point to its containing cell can be obtained with
6907: $ const PetscSFNode *cells;
6908: $ PetscInt nFound;
6909: $ const PetscInt *found;
6910: $
6911: $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6913: Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6914: the index of the cell in its rank's local numbering.
6916: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6917: @*/
6918: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6919: {
6926: if (*cellSF) {
6927: PetscMPIInt result;
6930: MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6931: if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6932: } else {
6933: PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6934: }
6935: if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6936: PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6937: (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6938: PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6939: return(0);
6940: }
6942: /*@
6943: DMGetOutputDM - Retrieve the DM associated with the layout for output
6945: Collective on dm
6947: Input Parameter:
6948: . dm - The original DM
6950: Output Parameter:
6951: . odm - The DM which provides the layout for output
6953: Level: intermediate
6955: .seealso: VecView(), DMGetGlobalSection()
6956: @*/
6957: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6958: {
6959: PetscSection section;
6960: PetscBool hasConstraints, ghasConstraints;
6966: DMGetLocalSection(dm, §ion);
6967: PetscSectionHasConstraints(section, &hasConstraints);
6968: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6969: if (!ghasConstraints) {
6970: *odm = dm;
6971: return(0);
6972: }
6973: if (!dm->dmBC) {
6974: PetscSection newSection, gsection;
6975: PetscSF sf;
6977: DMClone(dm, &dm->dmBC);
6978: DMCopyDisc(dm, dm->dmBC);
6979: PetscSectionClone(section, &newSection);
6980: DMSetLocalSection(dm->dmBC, newSection);
6981: PetscSectionDestroy(&newSection);
6982: DMGetPointSF(dm->dmBC, &sf);
6983: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6984: DMSetGlobalSection(dm->dmBC, gsection);
6985: PetscSectionDestroy(&gsection);
6986: }
6987: *odm = dm->dmBC;
6988: return(0);
6989: }
6991: /*@
6992: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6994: Input Parameter:
6995: . dm - The original DM
6997: Output Parameters:
6998: + num - The output sequence number
6999: - val - The output sequence value
7001: Level: intermediate
7003: Note: This is intended for output that should appear in sequence, for instance
7004: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7006: .seealso: VecView()
7007: @*/
7008: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7009: {
7014: return(0);
7015: }
7017: /*@
7018: DMSetOutputSequenceNumber - Set the sequence number/value for output
7020: Input Parameters:
7021: + dm - The original DM
7022: . num - The output sequence number
7023: - val - The output sequence value
7025: Level: intermediate
7027: Note: This is intended for output that should appear in sequence, for instance
7028: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7030: .seealso: VecView()
7031: @*/
7032: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7033: {
7036: dm->outputSequenceNum = num;
7037: dm->outputSequenceVal = val;
7038: return(0);
7039: }
7041: /*@C
7042: DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7044: Input Parameters:
7045: + dm - The original DM
7046: . name - The sequence name
7047: - num - The output sequence number
7049: Output Parameter:
7050: . val - The output sequence value
7052: Level: intermediate
7054: Note: This is intended for output that should appear in sequence, for instance
7055: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7057: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7058: @*/
7059: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7060: {
7061: PetscBool ishdf5;
7068: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7069: if (ishdf5) {
7070: #if defined(PETSC_HAVE_HDF5)
7071: PetscScalar value;
7073: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7074: *val = PetscRealPart(value);
7075: #endif
7076: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7077: return(0);
7078: }
7080: /*@
7081: DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7083: Not collective
7085: Input Parameter:
7086: . dm - The DM
7088: Output Parameter:
7089: . useNatural - The flag to build the mapping to a natural order during distribution
7091: Level: beginner
7093: .seealso: DMSetUseNatural(), DMCreate()
7094: @*/
7095: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7096: {
7100: *useNatural = dm->useNatural;
7101: return(0);
7102: }
7104: /*@
7105: DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7107: Collective on dm
7109: Input Parameters:
7110: + dm - The DM
7111: - useNatural - The flag to build the mapping to a natural order during distribution
7113: Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7115: Level: beginner
7117: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7118: @*/
7119: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7120: {
7124: dm->useNatural = useNatural;
7125: return(0);
7126: }
7129: /*@C
7130: DMCreateLabel - Create a label of the given name if it does not already exist
7132: Not Collective
7134: Input Parameters:
7135: + dm - The DM object
7136: - name - The label name
7138: Level: intermediate
7140: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7141: @*/
7142: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7143: {
7144: PetscBool flg;
7145: DMLabel label;
7151: DMHasLabel(dm, name, &flg);
7152: if (!flg) {
7153: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7154: DMAddLabel(dm, label);
7155: DMLabelDestroy(&label);
7156: }
7157: return(0);
7158: }
7160: /*@C
7161: DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7163: Not Collective
7165: Input Parameters:
7166: + dm - The DM object
7167: . name - The label name
7168: - point - The mesh point
7170: Output Parameter:
7171: . value - The label value for this point, or -1 if the point is not in the label
7173: Level: beginner
7175: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7176: @*/
7177: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7178: {
7179: DMLabel label;
7185: DMGetLabel(dm, name, &label);
7186: if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7187: DMLabelGetValue(label, point, value);
7188: return(0);
7189: }
7191: /*@C
7192: DMSetLabelValue - Add a point to a Sieve Label with given value
7194: Not Collective
7196: Input Parameters:
7197: + dm - The DM object
7198: . name - The label name
7199: . point - The mesh point
7200: - value - The label value for this point
7202: Output Parameter:
7204: Level: beginner
7206: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7207: @*/
7208: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7209: {
7210: DMLabel label;
7216: DMGetLabel(dm, name, &label);
7217: if (!label) {
7218: DMCreateLabel(dm, name);
7219: DMGetLabel(dm, name, &label);
7220: }
7221: DMLabelSetValue(label, point, value);
7222: return(0);
7223: }
7225: /*@C
7226: DMClearLabelValue - Remove a point from a Sieve Label with given value
7228: Not Collective
7230: Input Parameters:
7231: + dm - The DM object
7232: . name - The label name
7233: . point - The mesh point
7234: - value - The label value for this point
7236: Output Parameter:
7238: Level: beginner
7240: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7241: @*/
7242: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7243: {
7244: DMLabel label;
7250: DMGetLabel(dm, name, &label);
7251: if (!label) return(0);
7252: DMLabelClearValue(label, point, value);
7253: return(0);
7254: }
7256: /*@C
7257: DMGetLabelSize - Get the number of different integer ids in a Label
7259: Not Collective
7261: Input Parameters:
7262: + dm - The DM object
7263: - name - The label name
7265: Output Parameter:
7266: . size - The number of different integer ids, or 0 if the label does not exist
7268: Level: beginner
7270: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7271: @*/
7272: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7273: {
7274: DMLabel label;
7281: DMGetLabel(dm, name, &label);
7282: *size = 0;
7283: if (!label) return(0);
7284: DMLabelGetNumValues(label, size);
7285: return(0);
7286: }
7288: /*@C
7289: DMGetLabelIdIS - Get the integer ids in a label
7291: Not Collective
7293: Input Parameters:
7294: + mesh - The DM object
7295: - name - The label name
7297: Output Parameter:
7298: . ids - The integer ids, or NULL if the label does not exist
7300: Level: beginner
7302: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7303: @*/
7304: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7305: {
7306: DMLabel label;
7313: DMGetLabel(dm, name, &label);
7314: *ids = NULL;
7315: if (label) {
7316: DMLabelGetValueIS(label, ids);
7317: } else {
7318: /* returning an empty IS */
7319: ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7320: }
7321: return(0);
7322: }
7324: /*@C
7325: DMGetStratumSize - Get the number of points in a label stratum
7327: Not Collective
7329: Input Parameters:
7330: + dm - The DM object
7331: . name - The label name
7332: - value - The stratum value
7334: Output Parameter:
7335: . size - The stratum size
7337: Level: beginner
7339: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7340: @*/
7341: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7342: {
7343: DMLabel label;
7350: DMGetLabel(dm, name, &label);
7351: *size = 0;
7352: if (!label) return(0);
7353: DMLabelGetStratumSize(label, value, size);
7354: return(0);
7355: }
7357: /*@C
7358: DMGetStratumIS - Get the points in a label stratum
7360: Not Collective
7362: Input Parameters:
7363: + dm - The DM object
7364: . name - The label name
7365: - value - The stratum value
7367: Output Parameter:
7368: . points - The stratum points, or NULL if the label does not exist or does not have that value
7370: Level: beginner
7372: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7373: @*/
7374: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7375: {
7376: DMLabel label;
7383: DMGetLabel(dm, name, &label);
7384: *points = NULL;
7385: if (!label) return(0);
7386: DMLabelGetStratumIS(label, value, points);
7387: return(0);
7388: }
7390: /*@C
7391: DMSetStratumIS - Set the points in a label stratum
7393: Not Collective
7395: Input Parameters:
7396: + dm - The DM object
7397: . name - The label name
7398: . value - The stratum value
7399: - points - The stratum points
7401: Level: beginner
7403: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7404: @*/
7405: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7406: {
7407: DMLabel label;
7414: DMGetLabel(dm, name, &label);
7415: if (!label) return(0);
7416: DMLabelSetStratumIS(label, value, points);
7417: return(0);
7418: }
7420: /*@C
7421: DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7423: Not Collective
7425: Input Parameters:
7426: + dm - The DM object
7427: . name - The label name
7428: - value - The label value for this point
7430: Output Parameter:
7432: Level: beginner
7434: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7435: @*/
7436: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7437: {
7438: DMLabel label;
7444: DMGetLabel(dm, name, &label);
7445: if (!label) return(0);
7446: DMLabelClearStratum(label, value);
7447: return(0);
7448: }
7450: /*@
7451: DMGetNumLabels - Return the number of labels defined by the mesh
7453: Not Collective
7455: Input Parameter:
7456: . dm - The DM object
7458: Output Parameter:
7459: . numLabels - the number of Labels
7461: Level: intermediate
7463: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7464: @*/
7465: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7466: {
7467: DMLabelLink next = dm->labels;
7468: PetscInt n = 0;
7473: while (next) {++n; next = next->next;}
7474: *numLabels = n;
7475: return(0);
7476: }
7478: /*@C
7479: DMGetLabelName - Return the name of nth label
7481: Not Collective
7483: Input Parameters:
7484: + dm - The DM object
7485: - n - the label number
7487: Output Parameter:
7488: . name - the label name
7490: Level: intermediate
7492: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7493: @*/
7494: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7495: {
7496: DMLabelLink next = dm->labels;
7497: PetscInt l = 0;
7503: while (next) {
7504: if (l == n) {
7505: PetscObjectGetName((PetscObject) next->label, name);
7506: return(0);
7507: }
7508: ++l;
7509: next = next->next;
7510: }
7511: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7512: }
7514: /*@C
7515: DMHasLabel - Determine whether the mesh has a label of a given name
7517: Not Collective
7519: Input Parameters:
7520: + dm - The DM object
7521: - name - The label name
7523: Output Parameter:
7524: . hasLabel - PETSC_TRUE if the label is present
7526: Level: intermediate
7528: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7529: @*/
7530: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7531: {
7532: DMLabelLink next = dm->labels;
7533: const char *lname;
7540: *hasLabel = PETSC_FALSE;
7541: while (next) {
7542: PetscObjectGetName((PetscObject) next->label, &lname);
7543: PetscStrcmp(name, lname, hasLabel);
7544: if (*hasLabel) break;
7545: next = next->next;
7546: }
7547: return(0);
7548: }
7550: /*@C
7551: DMGetLabel - Return the label of a given name, or NULL
7553: Not Collective
7555: Input Parameters:
7556: + dm - The DM object
7557: - name - The label name
7559: Output Parameter:
7560: . label - The DMLabel, or NULL if the label is absent
7562: Level: intermediate
7564: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7565: @*/
7566: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7567: {
7568: DMLabelLink next = dm->labels;
7569: PetscBool hasLabel;
7570: const char *lname;
7577: *label = NULL;
7578: while (next) {
7579: PetscObjectGetName((PetscObject) next->label, &lname);
7580: PetscStrcmp(name, lname, &hasLabel);
7581: if (hasLabel) {
7582: *label = next->label;
7583: break;
7584: }
7585: next = next->next;
7586: }
7587: return(0);
7588: }
7590: /*@C
7591: DMGetLabelByNum - Return the nth label
7593: Not Collective
7595: Input Parameters:
7596: + dm - The DM object
7597: - n - the label number
7599: Output Parameter:
7600: . label - the label
7602: Level: intermediate
7604: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7605: @*/
7606: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7607: {
7608: DMLabelLink next = dm->labels;
7609: PetscInt l = 0;
7614: while (next) {
7615: if (l == n) {
7616: *label = next->label;
7617: return(0);
7618: }
7619: ++l;
7620: next = next->next;
7621: }
7622: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7623: }
7625: /*@C
7626: DMAddLabel - Add the label to this mesh
7628: Not Collective
7630: Input Parameters:
7631: + dm - The DM object
7632: - label - The DMLabel
7634: Level: developer
7636: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7637: @*/
7638: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7639: {
7640: DMLabelLink l, *p, tmpLabel;
7641: PetscBool hasLabel;
7642: const char *lname;
7643: PetscBool flg;
7648: PetscObjectGetName((PetscObject) label, &lname);
7649: DMHasLabel(dm, lname, &hasLabel);
7650: if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7651: PetscCalloc1(1, &tmpLabel);
7652: tmpLabel->label = label;
7653: tmpLabel->output = PETSC_TRUE;
7654: for (p=&dm->labels; (l=*p); p=&l->next) {}
7655: *p = tmpLabel;
7656: PetscObjectReference((PetscObject)label);
7657: PetscStrcmp(lname, "depth", &flg);
7658: if (flg) dm->depthLabel = label;
7659: PetscStrcmp(lname, "celltype", &flg);
7660: if (flg) dm->celltypeLabel = label;
7661: return(0);
7662: }
7664: /*@C
7665: DMRemoveLabel - Remove the label given by name from this mesh
7667: Not Collective
7669: Input Parameters:
7670: + dm - The DM object
7671: - name - The label name
7673: Output Parameter:
7674: . label - The DMLabel, or NULL if the label is absent
7676: Level: developer
7678: Notes:
7679: DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7680: DMLabelDestroy() on the label.
7682: DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7683: call DMLabelDestroy(). Instead, the label is returned and the user is
7684: responsible of calling DMLabelDestroy() at some point.
7686: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7687: @*/
7688: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7689: {
7690: DMLabelLink link, *pnext;
7691: PetscBool hasLabel;
7692: const char *lname;
7698: if (label) {
7700: *label = NULL;
7701: }
7702: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7703: PetscObjectGetName((PetscObject) link->label, &lname);
7704: PetscStrcmp(name, lname, &hasLabel);
7705: if (hasLabel) {
7706: *pnext = link->next; /* Remove from list */
7707: PetscStrcmp(name, "depth", &hasLabel);
7708: if (hasLabel) dm->depthLabel = NULL;
7709: PetscStrcmp(name, "celltype", &hasLabel);
7710: if (hasLabel) dm->celltypeLabel = NULL;
7711: if (label) *label = link->label;
7712: else {DMLabelDestroy(&link->label);}
7713: PetscFree(link);
7714: break;
7715: }
7716: }
7717: return(0);
7718: }
7720: /*@
7721: DMRemoveLabelBySelf - Remove the label from this mesh
7723: Not Collective
7725: Input Parameters:
7726: + dm - The DM object
7727: . label - (Optional) The DMLabel to be removed from the DM
7728: - failNotFound - Should it fail if the label is not found in the DM?
7730: Level: developer
7732: Notes:
7733: Only exactly the same instance is removed if found, name match is ignored.
7734: If the DM has an exclusive reference to the label, it gets destroyed and
7735: *label nullified.
7737: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7738: @*/
7739: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7740: {
7741: DMLabelLink link, *pnext;
7742: PetscBool hasLabel = PETSC_FALSE;
7748: if (!*label && !failNotFound) return(0);
7751: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7752: if (*label == link->label) {
7753: hasLabel = PETSC_TRUE;
7754: *pnext = link->next; /* Remove from list */
7755: if (*label == dm->depthLabel) dm->depthLabel = NULL;
7756: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7757: if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7758: DMLabelDestroy(&link->label);
7759: PetscFree(link);
7760: break;
7761: }
7762: }
7763: if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7764: return(0);
7765: }
7767: /*@C
7768: DMGetLabelOutput - Get the output flag for a given label
7770: Not Collective
7772: Input Parameters:
7773: + dm - The DM object
7774: - name - The label name
7776: Output Parameter:
7777: . output - The flag for output
7779: Level: developer
7781: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7782: @*/
7783: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7784: {
7785: DMLabelLink next = dm->labels;
7786: const char *lname;
7793: while (next) {
7794: PetscBool flg;
7796: PetscObjectGetName((PetscObject) next->label, &lname);
7797: PetscStrcmp(name, lname, &flg);
7798: if (flg) {*output = next->output; return(0);}
7799: next = next->next;
7800: }
7801: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7802: }
7804: /*@C
7805: DMSetLabelOutput - Set the output flag for a given label
7807: Not Collective
7809: Input Parameters:
7810: + dm - The DM object
7811: . name - The label name
7812: - output - The flag for output
7814: Level: developer
7816: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7817: @*/
7818: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7819: {
7820: DMLabelLink next = dm->labels;
7821: const char *lname;
7827: while (next) {
7828: PetscBool flg;
7830: PetscObjectGetName((PetscObject) next->label, &lname);
7831: PetscStrcmp(name, lname, &flg);
7832: if (flg) {next->output = output; return(0);}
7833: next = next->next;
7834: }
7835: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7836: }
7838: /*@
7839: DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7841: Collective on dmA
7843: Input Parameter:
7844: + dmA - The DM object with initial labels
7845: . dmB - The DM object with copied labels
7846: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7847: - all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7849: Level: intermediate
7851: Note: This is typically used when interpolating or otherwise adding to a mesh
7853: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7854: @*/
7855: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7856: {
7857: DMLabel label, labelNew;
7858: const char *name;
7859: PetscBool flg;
7860: DMLabelLink link;
7868: if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7869: if (dmA == dmB) return(0);
7870: for (link=dmA->labels; link; link=link->next) {
7871: label=link->label;
7872: PetscObjectGetName((PetscObject)label, &name);
7873: if (!all) {
7874: PetscStrcmp(name, "depth", &flg);
7875: if (flg) continue;
7876: PetscStrcmp(name, "dim", &flg);
7877: if (flg) continue;
7878: PetscStrcmp(name, "celltype", &flg);
7879: if (flg) continue;
7880: }
7881: if (mode==PETSC_COPY_VALUES) {
7882: DMLabelDuplicate(label, &labelNew);
7883: } else {
7884: labelNew = label;
7885: }
7886: DMAddLabel(dmB, labelNew);
7887: if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7888: }
7889: return(0);
7890: }
7892: /*@
7893: DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7895: Input Parameter:
7896: . dm - The DM object
7898: Output Parameter:
7899: . cdm - The coarse DM
7901: Level: intermediate
7903: .seealso: DMSetCoarseDM()
7904: @*/
7905: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7906: {
7910: *cdm = dm->coarseMesh;
7911: return(0);
7912: }
7914: /*@
7915: DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7917: Input Parameters:
7918: + dm - The DM object
7919: - cdm - The coarse DM
7921: Level: intermediate
7923: .seealso: DMGetCoarseDM()
7924: @*/
7925: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7926: {
7932: PetscObjectReference((PetscObject)cdm);
7933: DMDestroy(&dm->coarseMesh);
7934: dm->coarseMesh = cdm;
7935: return(0);
7936: }
7938: /*@
7939: DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7941: Input Parameter:
7942: . dm - The DM object
7944: Output Parameter:
7945: . fdm - The fine DM
7947: Level: intermediate
7949: .seealso: DMSetFineDM()
7950: @*/
7951: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7952: {
7956: *fdm = dm->fineMesh;
7957: return(0);
7958: }
7960: /*@
7961: DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7963: Input Parameters:
7964: + dm - The DM object
7965: - fdm - The fine DM
7967: Level: intermediate
7969: .seealso: DMGetFineDM()
7970: @*/
7971: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7972: {
7978: PetscObjectReference((PetscObject)fdm);
7979: DMDestroy(&dm->fineMesh);
7980: dm->fineMesh = fdm;
7981: return(0);
7982: }
7984: /*=== DMBoundary code ===*/
7986: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7987: {
7988: PetscInt d;
7992: for (d = 0; d < dm->Nds; ++d) {
7993: PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7994: }
7995: return(0);
7996: }
7998: /*@C
7999: DMAddBoundary - Add a boundary condition to the model
8001: Collective on dm
8003: Input Parameters:
8004: + dm - The DM, with a PetscDS that matches the problem being constrained
8005: . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8006: . name - The BC name
8007: . labelname - The label defining constrained points
8008: . field - The field to constrain
8009: . numcomps - The number of constrained field components (0 will constrain all fields)
8010: . comps - An array of constrained component numbers
8011: . bcFunc - A pointwise function giving boundary values
8012: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8013: . numids - The number of DMLabel ids for constrained points
8014: . ids - An array of ids for constrained points
8015: - ctx - An optional user context for bcFunc
8017: Options Database Keys:
8018: + -bc_<boundary name> <num> - Overrides the boundary ids
8019: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8021: Note:
8022: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8024: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8026: If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8028: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8029: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8030: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8031: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
8033: + dim - the spatial dimension
8034: . Nf - the number of fields
8035: . uOff - the offset into u[] and u_t[] for each field
8036: . uOff_x - the offset into u_x[] for each field
8037: . u - each field evaluated at the current point
8038: . u_t - the time derivative of each field evaluated at the current point
8039: . u_x - the gradient of each field evaluated at the current point
8040: . aOff - the offset into a[] and a_t[] for each auxiliary field
8041: . aOff_x - the offset into a_x[] for each auxiliary field
8042: . a - each auxiliary field evaluated at the current point
8043: . a_t - the time derivative of each auxiliary field evaluated at the current point
8044: . a_x - the gradient of auxiliary each field evaluated at the current point
8045: . t - current time
8046: . x - coordinates of the current point
8047: . numConstants - number of constant parameters
8048: . constants - constant parameters
8049: - bcval - output values at the current point
8051: Level: developer
8053: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8054: @*/
8055: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
8056: {
8057: PetscDS ds;
8066: DMGetDS(dm, &ds);
8067: DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8068: PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8069: return(0);
8070: }
8072: /*@
8073: DMGetNumBoundary - Get the number of registered BC
8075: Input Parameters:
8076: . dm - The mesh object
8078: Output Parameters:
8079: . numBd - The number of BC
8081: Level: intermediate
8083: .seealso: DMAddBoundary(), DMGetBoundary()
8084: @*/
8085: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8086: {
8087: PetscDS ds;
8092: DMGetDS(dm, &ds);
8093: PetscDSGetNumBoundary(ds, numBd);
8094: return(0);
8095: }
8097: /*@C
8098: DMGetBoundary - Get a model boundary condition
8100: Input Parameters:
8101: + dm - The mesh object
8102: - bd - The BC number
8104: Output Parameters:
8105: + type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8106: . name - The BC name
8107: . labelname - The label defining constrained points
8108: . field - The field to constrain
8109: . numcomps - The number of constrained field components
8110: . comps - An array of constrained component numbers
8111: . bcFunc - A pointwise function giving boundary values
8112: . bcFunc_t - A pointwise function giving the time derviative of the boundary values
8113: . numids - The number of DMLabel ids for constrained points
8114: . ids - An array of ids for constrained points
8115: - ctx - An optional user context for bcFunc
8117: Options Database Keys:
8118: + -bc_<boundary name> <num> - Overrides the boundary ids
8119: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8121: Level: developer
8123: .seealso: DMAddBoundary()
8124: @*/
8125: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
8126: {
8127: PetscDS ds;
8132: DMGetDS(dm, &ds);
8133: PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8134: return(0);
8135: }
8137: static PetscErrorCode DMPopulateBoundary(DM dm)
8138: {
8139: PetscDS ds;
8140: DMBoundary *lastnext;
8141: DSBoundary dsbound;
8145: DMGetDS(dm, &ds);
8146: dsbound = ds->boundary;
8147: if (dm->boundary) {
8148: DMBoundary next = dm->boundary;
8150: /* quick check to see if the PetscDS has changed */
8151: if (next->dsboundary == dsbound) return(0);
8152: /* the PetscDS has changed: tear down and rebuild */
8153: while (next) {
8154: DMBoundary b = next;
8156: next = b->next;
8157: PetscFree(b);
8158: }
8159: dm->boundary = NULL;
8160: }
8162: lastnext = &(dm->boundary);
8163: while (dsbound) {
8164: DMBoundary dmbound;
8166: PetscNew(&dmbound);
8167: dmbound->dsboundary = dsbound;
8168: DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8169: if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8170: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8171: *lastnext = dmbound;
8172: lastnext = &(dmbound->next);
8173: dsbound = dsbound->next;
8174: }
8175: return(0);
8176: }
8178: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8179: {
8180: DMBoundary b;
8186: *isBd = PETSC_FALSE;
8187: DMPopulateBoundary(dm);
8188: b = dm->boundary;
8189: while (b && !(*isBd)) {
8190: DMLabel label = b->label;
8191: DSBoundary dsb = b->dsboundary;
8193: if (label) {
8194: PetscInt i;
8196: for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8197: DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8198: }
8199: }
8200: b = b->next;
8201: }
8202: return(0);
8203: }
8205: /*@C
8206: DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8208: Collective on DM
8210: Input Parameters:
8211: + dm - The DM
8212: . time - The time
8213: . funcs - The coordinate functions to evaluate, one per field
8214: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8215: - mode - The insertion mode for values
8217: Output Parameter:
8218: . X - vector
8220: Calling sequence of func:
8221: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8223: + dim - The spatial dimension
8224: . time - The time at which to sample
8225: . x - The coordinates
8226: . Nf - The number of fields
8227: . u - The output field values
8228: - ctx - optional user-defined function context
8230: Level: developer
8232: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8233: @*/
8234: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8235: {
8236: Vec localX;
8241: DMGetLocalVector(dm, &localX);
8242: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8243: DMLocalToGlobalBegin(dm, localX, mode, X);
8244: DMLocalToGlobalEnd(dm, localX, mode, X);
8245: DMRestoreLocalVector(dm, &localX);
8246: return(0);
8247: }
8249: /*@C
8250: DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8252: Not collective
8254: Input Parameters:
8255: + dm - The DM
8256: . time - The time
8257: . funcs - The coordinate functions to evaluate, one per field
8258: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8259: - mode - The insertion mode for values
8261: Output Parameter:
8262: . localX - vector
8264: Calling sequence of func:
8265: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8267: + dim - The spatial dimension
8268: . x - The coordinates
8269: . Nf - The number of fields
8270: . u - The output field values
8271: - ctx - optional user-defined function context
8273: Level: developer
8275: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8276: @*/
8277: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8278: {
8284: if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8285: (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8286: return(0);
8287: }
8289: /*@C
8290: 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.
8292: Collective on DM
8294: Input Parameters:
8295: + dm - The DM
8296: . time - The time
8297: . label - The DMLabel selecting the portion of the mesh for projection
8298: . funcs - The coordinate functions to evaluate, one per field
8299: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8300: - mode - The insertion mode for values
8302: Output Parameter:
8303: . X - vector
8305: Calling sequence of func:
8306: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8308: + dim - The spatial dimension
8309: . x - The coordinates
8310: . Nf - The number of fields
8311: . u - The output field values
8312: - ctx - optional user-defined function context
8314: Level: developer
8316: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8317: @*/
8318: 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)
8319: {
8320: Vec localX;
8325: DMGetLocalVector(dm, &localX);
8326: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8327: DMLocalToGlobalBegin(dm, localX, mode, X);
8328: DMLocalToGlobalEnd(dm, localX, mode, X);
8329: DMRestoreLocalVector(dm, &localX);
8330: return(0);
8331: }
8333: /*@C
8334: 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.
8336: Not collective
8338: Input Parameters:
8339: + dm - The DM
8340: . time - The time
8341: . label - The DMLabel selecting the portion of the mesh for projection
8342: . funcs - The coordinate functions to evaluate, one per field
8343: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8344: - mode - The insertion mode for values
8346: Output Parameter:
8347: . localX - vector
8349: Calling sequence of func:
8350: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8352: + dim - The spatial dimension
8353: . x - The coordinates
8354: . Nf - The number of fields
8355: . u - The output field values
8356: - ctx - optional user-defined function context
8358: Level: developer
8360: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8361: @*/
8362: 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)
8363: {
8369: if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8370: (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8371: return(0);
8372: }
8374: /*@C
8375: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8377: Not collective
8379: Input Parameters:
8380: + dm - The DM
8381: . time - The time
8382: . localU - The input field vector
8383: . funcs - The functions to evaluate, one per field
8384: - mode - The insertion mode for values
8386: Output Parameter:
8387: . localX - The output vector
8389: Calling sequence of func:
8390: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8391: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8392: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8393: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8395: + dim - The spatial dimension
8396: . Nf - The number of input fields
8397: . NfAux - The number of input auxiliary fields
8398: . uOff - The offset of each field in u[]
8399: . uOff_x - The offset of each field in u_x[]
8400: . u - The field values at this point in space
8401: . u_t - The field time derivative at this point in space (or NULL)
8402: . u_x - The field derivatives at this point in space
8403: . aOff - The offset of each auxiliary field in u[]
8404: . aOff_x - The offset of each auxiliary field in u_x[]
8405: . a - The auxiliary field values at this point in space
8406: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8407: . a_x - The auxiliary field derivatives at this point in space
8408: . t - The current time
8409: . x - The coordinates of this point
8410: . numConstants - The number of constants
8411: . constants - The value of each constant
8412: - f - The value of the function at this point in space
8414: 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.
8415: 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
8416: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8417: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8419: Level: intermediate
8421: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8422: @*/
8423: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8424: void (**funcs)(PetscInt, PetscInt, PetscInt,
8425: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8426: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8427: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8428: InsertMode mode, Vec localX)
8429: {
8436: if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8437: (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8438: return(0);
8439: }
8441: /*@C
8442: 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.
8444: Not collective
8446: Input Parameters:
8447: + dm - The DM
8448: . time - The time
8449: . label - The DMLabel marking the portion of the domain to output
8450: . numIds - The number of label ids to use
8451: . ids - The label ids to use for marking
8452: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8453: . comps - The components to set in the output, or NULL for all components
8454: . localU - The input field vector
8455: . funcs - The functions to evaluate, one per field
8456: - mode - The insertion mode for values
8458: Output Parameter:
8459: . localX - The output vector
8461: Calling sequence of func:
8462: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8463: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8464: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8465: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8467: + dim - The spatial dimension
8468: . Nf - The number of input fields
8469: . NfAux - The number of input auxiliary fields
8470: . uOff - The offset of each field in u[]
8471: . uOff_x - The offset of each field in u_x[]
8472: . u - The field values at this point in space
8473: . u_t - The field time derivative at this point in space (or NULL)
8474: . u_x - The field derivatives at this point in space
8475: . aOff - The offset of each auxiliary field in u[]
8476: . aOff_x - The offset of each auxiliary field in u_x[]
8477: . a - The auxiliary field values at this point in space
8478: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8479: . a_x - The auxiliary field derivatives at this point in space
8480: . t - The current time
8481: . x - The coordinates of this point
8482: . numConstants - The number of constants
8483: . constants - The value of each constant
8484: - f - The value of the function at this point in space
8486: 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.
8487: 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
8488: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8489: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8491: Level: intermediate
8493: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8494: @*/
8495: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8496: void (**funcs)(PetscInt, PetscInt, PetscInt,
8497: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8498: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8499: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8500: InsertMode mode, Vec localX)
8501: {
8508: if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8509: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8510: return(0);
8511: }
8513: /*@C
8514: 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.
8516: Not collective
8518: Input Parameters:
8519: + dm - The DM
8520: . time - The time
8521: . label - The DMLabel marking the portion of the domain boundary to output
8522: . numIds - The number of label ids to use
8523: . ids - The label ids to use for marking
8524: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8525: . comps - The components to set in the output, or NULL for all components
8526: . localU - The input field vector
8527: . funcs - The functions to evaluate, one per field
8528: - mode - The insertion mode for values
8530: Output Parameter:
8531: . localX - The output vector
8533: Calling sequence of func:
8534: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8535: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8536: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8537: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8539: + dim - The spatial dimension
8540: . Nf - The number of input fields
8541: . NfAux - The number of input auxiliary fields
8542: . uOff - The offset of each field in u[]
8543: . uOff_x - The offset of each field in u_x[]
8544: . u - The field values at this point in space
8545: . u_t - The field time derivative at this point in space (or NULL)
8546: . u_x - The field derivatives at this point in space
8547: . aOff - The offset of each auxiliary field in u[]
8548: . aOff_x - The offset of each auxiliary field in u_x[]
8549: . a - The auxiliary field values at this point in space
8550: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8551: . a_x - The auxiliary field derivatives at this point in space
8552: . t - The current time
8553: . x - The coordinates of this point
8554: . n - The face normal
8555: . numConstants - The number of constants
8556: . constants - The value of each constant
8557: - f - The value of the function at this point in space
8559: Note:
8560: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8561: 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
8562: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8563: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8565: Level: intermediate
8567: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8568: @*/
8569: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8570: void (**funcs)(PetscInt, PetscInt, PetscInt,
8571: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8572: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8573: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8574: InsertMode mode, Vec localX)
8575: {
8582: if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8583: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8584: return(0);
8585: }
8587: /*@C
8588: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8590: Input Parameters:
8591: + dm - The DM
8592: . time - The time
8593: . funcs - The functions to evaluate for each field component
8594: . ctxs - Optional array of contexts to pass to each function, or NULL.
8595: - X - The coefficient vector u_h, a global vector
8597: Output Parameter:
8598: . diff - The diff ||u - u_h||_2
8600: Level: developer
8602: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8603: @*/
8604: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8605: {
8611: if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8612: (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8613: return(0);
8614: }
8616: /*@C
8617: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8619: Collective on dm
8621: Input Parameters:
8622: + dm - The DM
8623: , time - The time
8624: . funcs - The gradient functions to evaluate for each field component
8625: . ctxs - Optional array of contexts to pass to each function, or NULL.
8626: . X - The coefficient vector u_h, a global vector
8627: - n - The vector to project along
8629: Output Parameter:
8630: . diff - The diff ||(grad u - grad u_h) . n||_2
8632: Level: developer
8634: .seealso: DMProjectFunction(), DMComputeL2Diff()
8635: @*/
8636: 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)
8637: {
8643: if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8644: (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8645: return(0);
8646: }
8648: /*@C
8649: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8651: Collective on dm
8653: Input Parameters:
8654: + dm - The DM
8655: . time - The time
8656: . funcs - The functions to evaluate for each field component
8657: . ctxs - Optional array of contexts to pass to each function, or NULL.
8658: - X - The coefficient vector u_h, a global vector
8660: Output Parameter:
8661: . diff - The array of differences, ||u^f - u^f_h||_2
8663: Level: developer
8665: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8666: @*/
8667: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8668: {
8674: if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8675: (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8676: return(0);
8677: }
8679: /*@C
8680: DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags. Specific implementations of DM maybe have
8681: specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8683: Collective on dm
8685: Input parameters:
8686: + dm - the pre-adaptation DM object
8687: - label - label with the flags
8689: Output parameters:
8690: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8692: Level: intermediate
8694: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8695: @*/
8696: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8697: {
8704: *dmAdapt = NULL;
8705: if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8706: (dm->ops->adaptlabel)(dm, label, dmAdapt);
8707: return(0);
8708: }
8710: /*@C
8711: DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8713: Input Parameters:
8714: + dm - The DM object
8715: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8716: - 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_".
8718: Output Parameter:
8719: . dmAdapt - Pointer to the DM object containing the adapted mesh
8721: Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8723: Level: advanced
8725: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8726: @*/
8727: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8728: {
8736: *dmAdapt = NULL;
8737: if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8738: (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8739: return(0);
8740: }
8742: /*@C
8743: DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8745: Not Collective
8747: Input Parameter:
8748: . dm - The DM
8750: Output Parameters:
8751: + nranks - the number of neighbours
8752: - ranks - the neighbors ranks
8754: Notes:
8755: Do not free the array, it is freed when the DM is destroyed.
8757: Level: beginner
8759: .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8760: @*/
8761: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8762: {
8767: if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8768: (dm->ops->getneighbors)(dm,nranks,ranks);
8769: return(0);
8770: }
8772: #include <petsc/private/matimpl.h>
8774: /*
8775: Converts the input vector to a ghosted vector and then calls the standard coloring code.
8776: This has be a different function because it requires DM which is not defined in the Mat library
8777: */
8778: PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8779: {
8783: if (coloring->ctype == IS_COLORING_LOCAL) {
8784: Vec x1local;
8785: DM dm;
8786: MatGetDM(J,&dm);
8787: if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8788: DMGetLocalVector(dm,&x1local);
8789: DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8790: DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8791: x1 = x1local;
8792: }
8793: MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8794: if (coloring->ctype == IS_COLORING_LOCAL) {
8795: DM dm;
8796: MatGetDM(J,&dm);
8797: DMRestoreLocalVector(dm,&x1);
8798: }
8799: return(0);
8800: }
8802: /*@
8803: MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
8805: Input Parameter:
8806: . coloring - the MatFDColoring object
8808: Developer Notes:
8809: this routine exists because the PETSc Mat library does not know about the DM objects
8811: Level: advanced
8813: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8814: @*/
8815: PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8816: {
8818: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8819: return(0);
8820: }
8822: /*@
8823: DMGetCompatibility - determine if two DMs are compatible
8825: Collective
8827: Input Parameters:
8828: + dm1 - the first DM
8829: - dm2 - the second DM
8831: Output Parameters:
8832: + compatible - whether or not the two DMs are compatible
8833: - set - whether or not the compatible value was set
8835: Notes:
8836: Two DMs are deemed compatible if they represent the same parallel decomposition
8837: of the same topology. This implies that the section (field data) on one
8838: "makes sense" with respect to the topology and parallel decomposition of the other.
8839: Loosely speaking, compatible DMs represent the same domain and parallel
8840: decomposition, but hold different data.
8842: Typically, one would confirm compatibility if intending to simultaneously iterate
8843: over a pair of vectors obtained from different DMs.
8845: For example, two DMDA objects are compatible if they have the same local
8846: and global sizes and the same stencil width. They can have different numbers
8847: of degrees of freedom per node. Thus, one could use the node numbering from
8848: either DM in bounds for a loop over vectors derived from either DM.
8850: Consider the operation of summing data living on a 2-dof DMDA to data living
8851: on a 1-dof DMDA, which should be compatible, as in the following snippet.
8852: .vb
8853: ...
8854: DMGetCompatibility(da1,da2,&compatible,&set);
8855: if (set && compatible) {
8856: DMDAVecGetArrayDOF(da1,vec1,&arr1);
8857: DMDAVecGetArrayDOF(da2,vec2,&arr2);
8858: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8859: for (j=y; j<y+n; ++j) {
8860: for (i=x; i<x+m, ++i) {
8861: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8862: }
8863: }
8864: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8865: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8866: } else {
8867: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8868: }
8869: ...
8870: .ve
8872: Checking compatibility might be expensive for a given implementation of DM,
8873: or might be impossible to unambiguously confirm or deny. For this reason,
8874: this function may decline to determine compatibility, and hence users should
8875: always check the "set" output parameter.
8877: A DM is always compatible with itself.
8879: In the current implementation, DMs which live on "unequal" communicators
8880: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8881: incompatible.
8883: This function is labeled "Collective," as information about all subdomains
8884: is required on each rank. However, in DM implementations which store all this
8885: information locally, this function may be merely "Logically Collective".
8887: Developer Notes:
8888: Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8889: iff B is compatible with A. Thus, this function checks the implementations
8890: of both dm and dmc (if they are of different types), attempting to determine
8891: compatibility. It is left to DM implementers to ensure that symmetry is
8892: preserved. The simplest way to do this is, when implementing type-specific
8893: logic for this function, is to check for existing logic in the implementation
8894: of other DM types and let *set = PETSC_FALSE if found.
8896: Level: advanced
8898: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8899: @*/
8901: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8902: {
8904: PetscMPIInt compareResult;
8905: DMType type,type2;
8906: PetscBool sameType;
8912: /* Declare a DM compatible with itself */
8913: if (dm1 == dm2) {
8914: *set = PETSC_TRUE;
8915: *compatible = PETSC_TRUE;
8916: return(0);
8917: }
8919: /* Declare a DM incompatible with a DM that lives on an "unequal"
8920: communicator. Note that this does not preclude compatibility with
8921: DMs living on "congruent" or "similar" communicators, but this must be
8922: determined by the implementation-specific logic */
8923: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
8924: if (compareResult == MPI_UNEQUAL) {
8925: *set = PETSC_TRUE;
8926: *compatible = PETSC_FALSE;
8927: return(0);
8928: }
8930: /* Pass to the implementation-specific routine, if one exists. */
8931: if (dm1->ops->getcompatibility) {
8932: (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
8933: if (*set) return(0);
8934: }
8936: /* If dm1 and dm2 are of different types, then attempt to check compatibility
8937: with an implementation of this function from dm2 */
8938: DMGetType(dm1,&type);
8939: DMGetType(dm2,&type2);
8940: PetscStrcmp(type,type2,&sameType);
8941: if (!sameType && dm2->ops->getcompatibility) {
8942: (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
8943: } else {
8944: *set = PETSC_FALSE;
8945: }
8946: return(0);
8947: }
8949: /*@C
8950: DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
8952: Logically Collective on DM
8954: Input Parameters:
8955: + DM - the DM
8956: . f - the monitor function
8957: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8958: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8960: Options Database Keys:
8961: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8962: does not cancel those set via the options database.
8964: Notes:
8965: Several different monitoring routines may be set by calling
8966: DMMonitorSet() multiple times; all will be called in the
8967: order in which they were set.
8969: Fortran Notes:
8970: Only a single monitor function can be set for each DM object
8972: Level: intermediate
8974: .seealso: DMMonitorCancel()
8975: @*/
8976: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8977: {
8978: PetscInt m;
8983: for (m = 0; m < dm->numbermonitors; ++m) {
8984: PetscBool identical;
8986: PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8987: if (identical) return(0);
8988: }
8989: if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8990: dm->monitor[dm->numbermonitors] = f;
8991: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
8992: dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8993: return(0);
8994: }
8996: /*@
8997: DMMonitorCancel - Clears all the monitor functions for a DM object.
8999: Logically Collective on DM
9001: Input Parameter:
9002: . dm - the DM
9004: Options Database Key:
9005: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9006: into a code by calls to DMonitorSet(), but does not cancel those
9007: set via the options database
9009: Notes:
9010: There is no way to clear one specific monitor from a DM object.
9012: Level: intermediate
9014: .seealso: DMMonitorSet()
9015: @*/
9016: PetscErrorCode DMMonitorCancel(DM dm)
9017: {
9019: PetscInt m;
9023: for (m = 0; m < dm->numbermonitors; ++m) {
9024: if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9025: }
9026: dm->numbermonitors = 0;
9027: return(0);
9028: }
9030: /*@C
9031: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9033: Collective on DM
9035: Input Parameters:
9036: + dm - DM object you wish to monitor
9037: . name - the monitor type one is seeking
9038: . help - message indicating what monitoring is done
9039: . manual - manual page for the monitor
9040: . monitor - the monitor function
9041: - 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
9043: Output Parameter:
9044: . flg - Flag set if the monitor was created
9046: Level: developer
9048: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9049: PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9050: PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9051: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9052: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9053: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9054: PetscOptionsFList(), PetscOptionsEList()
9055: @*/
9056: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9057: {
9058: PetscViewer viewer;
9059: PetscViewerFormat format;
9060: PetscErrorCode ierr;
9064: PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9065: if (*flg) {
9066: PetscViewerAndFormat *vf;
9068: PetscViewerAndFormatCreate(viewer, format, &vf);
9069: PetscObjectDereference((PetscObject) viewer);
9070: if (monitorsetup) {(*monitorsetup)(dm, vf);}
9071: DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9072: }
9073: return(0);
9074: }
9076: /*@
9077: DMMonitor - runs the user provided monitor routines, if they exist
9079: Collective on DM
9081: Input Parameters:
9082: . dm - The DM
9084: Level: developer
9086: .seealso: DMMonitorSet()
9087: @*/
9088: PetscErrorCode DMMonitor(DM dm)
9089: {
9090: PetscInt m;
9094: if (!dm) return(0);
9096: for (m = 0; m < dm->numbermonitors; ++m) {
9097: (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9098: }
9099: return(0);
9100: }