Actual source code: dm.c
1: #include <petscvec.h>
2: #include <petsc/private/dmimpl.h>
3: #include <petsc/private/dmlabelimpl.h>
4: #include <petsc/private/petscdsimpl.h>
5: #include <petscdmplex.h>
6: #include <petscdmfield.h>
7: #include <petscsf.h>
8: #include <petscds.h>
10: #if defined(PETSC_HAVE_VALGRIND)
11: # include <valgrind/memcheck.h>
12: #endif
14: PetscClassId DM_CLASSID;
15: PetscClassId DMLABEL_CLASSID;
16: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load, DM_AdaptInterpolator;
18: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
19: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","ESSENTIAL_BD_FIELD","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
20: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
22: /*@
23: DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
25: If you never call DMSetType() it will generate an
26: error when you try to use the vector.
28: Collective
30: Input Parameter:
31: . comm - The communicator for the DM object
33: Output Parameter:
34: . dm - The DM object
36: Level: beginner
38: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
39: @*/
40: PetscErrorCode DMCreate(MPI_Comm comm,DM *dm)
41: {
42: DM v;
43: PetscDS ds;
48: *dm = NULL;
49: DMInitializePackage();
51: PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);
53: v->setupcalled = PETSC_FALSE;
54: v->setfromoptionscalled = PETSC_FALSE;
55: v->ltogmap = NULL;
56: v->bs = 1;
57: v->coloringtype = IS_COLORING_GLOBAL;
58: PetscSFCreate(comm, &v->sf);
59: PetscSFCreate(comm, &v->sectionSF);
60: v->labels = NULL;
61: v->adjacency[0] = PETSC_FALSE;
62: v->adjacency[1] = PETSC_TRUE;
63: v->depthLabel = NULL;
64: v->celltypeLabel = NULL;
65: v->localSection = NULL;
66: v->globalSection = NULL;
67: v->defaultConstraintSection = NULL;
68: v->defaultConstraintMat = NULL;
69: v->L = NULL;
70: v->maxCell = NULL;
71: v->bdtype = NULL;
72: v->dimEmbed = PETSC_DEFAULT;
73: v->dim = PETSC_DETERMINE;
74: {
75: PetscInt i;
76: for (i = 0; i < 10; ++i) {
77: v->nullspaceConstructors[i] = NULL;
78: v->nearnullspaceConstructors[i] = NULL;
79: }
80: }
81: PetscDSCreate(PetscObjectComm((PetscObject) v), &ds);
82: DMSetRegionDS(v, NULL, NULL, ds);
83: PetscDSDestroy(&ds);
84: v->dmBC = NULL;
85: v->coarseMesh = NULL;
86: v->outputSequenceNum = -1;
87: v->outputSequenceVal = 0.0;
88: DMSetVecType(v,VECSTANDARD);
89: DMSetMatType(v,MATAIJ);
91: *dm = v;
92: return(0);
93: }
95: /*@
96: DMClone - Creates a DM object with the same topology as the original.
98: Collective
100: Input Parameter:
101: . dm - The original DM object
103: Output Parameter:
104: . newdm - The new DM object
106: Level: beginner
108: Notes:
109: For some DM implementations this is a shallow clone, the result of which may share (referent counted) information with its parent. For example,
110: DMClone() applied to a DMPLEX object will result in a new DMPLEX that shares the topology with the original DMPLEX. It does not
111: share the PetscSection of the original DM.
113: The clone is considered set up iff the original is.
115: .seealso: DMDestroy(), DMCreate(), DMSetType(), DMSetLocalSection(), DMSetGlobalSection()
117: @*/
118: PetscErrorCode DMClone(DM dm, DM *newdm)
119: {
120: PetscSF sf;
121: Vec coords;
122: void *ctx;
123: PetscInt dim, cdim;
129: DMCreate(PetscObjectComm((PetscObject) dm), newdm);
130: DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
131: (*newdm)->leveldown = dm->leveldown;
132: (*newdm)->levelup = dm->levelup;
133: (*newdm)->prealloc_only = dm->prealloc_only;
134: PetscFree((*newdm)->vectype);
135: PetscStrallocpy(dm->vectype,(char**)&(*newdm)->vectype);
136: PetscFree((*newdm)->mattype);
137: PetscStrallocpy(dm->mattype,(char**)&(*newdm)->mattype);
138: DMGetDimension(dm, &dim);
139: DMSetDimension(*newdm, dim);
140: if (dm->ops->clone) {
141: (*dm->ops->clone)(dm, newdm);
142: }
143: (*newdm)->setupcalled = dm->setupcalled;
144: DMGetPointSF(dm, &sf);
145: DMSetPointSF(*newdm, sf);
146: DMGetApplicationContext(dm, &ctx);
147: DMSetApplicationContext(*newdm, ctx);
148: if (dm->coordinateDM) {
149: DM ncdm;
150: PetscSection cs;
151: PetscInt pEnd = -1, pEndMax = -1;
153: DMGetLocalSection(dm->coordinateDM, &cs);
154: if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
155: MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
156: if (pEndMax >= 0) {
157: DMClone(dm->coordinateDM, &ncdm);
158: DMCopyDisc(dm->coordinateDM, ncdm);
159: DMSetLocalSection(ncdm, cs);
160: DMSetCoordinateDM(*newdm, ncdm);
161: DMDestroy(&ncdm);
162: }
163: }
164: DMGetCoordinateDim(dm, &cdim);
165: DMSetCoordinateDim(*newdm, cdim);
166: DMGetCoordinatesLocal(dm, &coords);
167: if (coords) {
168: DMSetCoordinatesLocal(*newdm, coords);
169: } else {
170: DMGetCoordinates(dm, &coords);
171: if (coords) {DMSetCoordinates(*newdm, coords);}
172: }
173: {
174: PetscBool isper;
175: const PetscReal *maxCell, *L;
176: const DMBoundaryType *bd;
177: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
178: DMSetPeriodicity(*newdm, isper, maxCell, L, bd);
179: }
180: {
181: PetscBool useCone, useClosure;
183: DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
184: DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
185: }
186: return(0);
187: }
189: /*@C
190: DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
192: Logically Collective on da
194: Input Parameter:
195: + da - initial distributed array
196: . ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL
198: Options Database:
199: . -dm_vec_type ctype
201: Level: intermediate
203: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
204: @*/
205: PetscErrorCode DMSetVecType(DM da,VecType ctype)
206: {
211: PetscFree(da->vectype);
212: PetscStrallocpy(ctype,(char**)&da->vectype);
213: return(0);
214: }
216: /*@C
217: DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
219: Logically Collective on da
221: Input Parameter:
222: . da - initial distributed array
224: Output Parameter:
225: . ctype - the vector type
227: Level: intermediate
229: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
230: @*/
231: PetscErrorCode DMGetVecType(DM da,VecType *ctype)
232: {
235: *ctype = da->vectype;
236: return(0);
237: }
239: /*@
240: VecGetDM - Gets the DM defining the data layout of the vector
242: Not collective
244: Input Parameter:
245: . v - The Vec
247: Output Parameter:
248: . dm - The DM
250: Level: intermediate
252: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
253: @*/
254: PetscErrorCode VecGetDM(Vec v, DM *dm)
255: {
261: PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
262: return(0);
263: }
265: /*@
266: VecSetDM - Sets the DM defining the data layout of the vector.
268: Not collective
270: Input Parameters:
271: + v - The Vec
272: - dm - The DM
274: 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.
276: Level: intermediate
278: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
279: @*/
280: PetscErrorCode VecSetDM(Vec v, DM dm)
281: {
287: PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
288: return(0);
289: }
291: /*@C
292: DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM
294: Logically Collective on dm
296: Input Parameters:
297: + dm - the DM context
298: - ctype - the matrix type
300: Options Database:
301: . -dm_is_coloring_type - global or local
303: Level: intermediate
305: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
306: DMGetISColoringType()
307: @*/
308: PetscErrorCode DMSetISColoringType(DM dm,ISColoringType ctype)
309: {
312: dm->coloringtype = ctype;
313: return(0);
314: }
316: /*@C
317: DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM
319: Logically Collective on dm
321: Input Parameter:
322: . dm - the DM context
324: Output Parameter:
325: . ctype - the matrix type
327: Options Database:
328: . -dm_is_coloring_type - global or local
330: Level: intermediate
332: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
333: DMGetISColoringType()
334: @*/
335: PetscErrorCode DMGetISColoringType(DM dm,ISColoringType *ctype)
336: {
339: *ctype = dm->coloringtype;
340: return(0);
341: }
343: /*@C
344: DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
346: Logically Collective on dm
348: Input Parameters:
349: + dm - the DM context
350: - ctype - the matrix type
352: Options Database:
353: . -dm_mat_type ctype
355: Level: intermediate
357: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
358: @*/
359: PetscErrorCode DMSetMatType(DM dm,MatType ctype)
360: {
365: PetscFree(dm->mattype);
366: PetscStrallocpy(ctype,(char**)&dm->mattype);
367: return(0);
368: }
370: /*@C
371: DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
373: Logically Collective on dm
375: Input Parameter:
376: . dm - the DM context
378: Output Parameter:
379: . ctype - the matrix type
381: Options Database:
382: . -dm_mat_type ctype
384: Level: intermediate
386: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
387: @*/
388: PetscErrorCode DMGetMatType(DM dm,MatType *ctype)
389: {
392: *ctype = dm->mattype;
393: return(0);
394: }
396: /*@
397: MatGetDM - Gets the DM defining the data layout of the matrix
399: Not collective
401: Input Parameter:
402: . A - The Mat
404: Output Parameter:
405: . dm - The DM
407: Level: intermediate
409: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
410: the Mat through a PetscObjectCompose() operation
412: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
413: @*/
414: PetscErrorCode MatGetDM(Mat A, DM *dm)
415: {
421: PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
422: return(0);
423: }
425: /*@
426: MatSetDM - Sets the DM defining the data layout of the matrix
428: Not collective
430: Input Parameters:
431: + A - The Mat
432: - dm - The DM
434: Level: intermediate
436: Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
437: the Mat through a PetscObjectCompose() operation
440: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
441: @*/
442: PetscErrorCode MatSetDM(Mat A, DM dm)
443: {
449: PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
450: return(0);
451: }
453: /*@C
454: DMSetOptionsPrefix - Sets the prefix used for searching for all
455: DM options in the database.
457: Logically Collective on dm
459: Input Parameter:
460: + da - the DM context
461: - prefix - the prefix to prepend to all option names
463: Notes:
464: A hyphen (-) must NOT be given at the beginning of the prefix name.
465: The first character of all runtime options is AUTOMATICALLY the hyphen.
467: Level: advanced
469: .seealso: DMSetFromOptions()
470: @*/
471: PetscErrorCode DMSetOptionsPrefix(DM dm,const char prefix[])
472: {
477: PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
478: if (dm->sf) {
479: PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
480: }
481: if (dm->sectionSF) {
482: PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
483: }
484: return(0);
485: }
487: /*@C
488: DMAppendOptionsPrefix - Appends to the prefix used for searching for all
489: DM options in the database.
491: Logically Collective on dm
493: Input Parameters:
494: + dm - the DM context
495: - prefix - the prefix string to prepend to all DM option requests
497: Notes:
498: A hyphen (-) must NOT be given at the beginning of the prefix name.
499: The first character of all runtime options is AUTOMATICALLY the hyphen.
501: Level: advanced
503: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
504: @*/
505: PetscErrorCode DMAppendOptionsPrefix(DM dm,const char prefix[])
506: {
511: PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
512: return(0);
513: }
515: /*@C
516: DMGetOptionsPrefix - Gets the prefix used for searching for all
517: DM options in the database.
519: Not Collective
521: Input Parameters:
522: . dm - the DM context
524: Output Parameters:
525: . prefix - pointer to the prefix string used is returned
527: Notes:
528: On the fortran side, the user should pass in a string 'prefix' of
529: sufficient length to hold the prefix.
531: Level: advanced
533: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
534: @*/
535: PetscErrorCode DMGetOptionsPrefix(DM dm,const char *prefix[])
536: {
541: PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
542: return(0);
543: }
545: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
546: {
547: PetscInt refct = ((PetscObject) dm)->refct;
551: *ncrefct = 0;
552: if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
553: refct--;
554: if (recurseCoarse) {
555: PetscInt coarseCount;
557: DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
558: refct += coarseCount;
559: }
560: }
561: if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
562: refct--;
563: if (recurseFine) {
564: PetscInt fineCount;
566: DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
567: refct += fineCount;
568: }
569: }
570: *ncrefct = refct;
571: return(0);
572: }
574: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
575: {
576: DMLabelLink next = dm->labels;
580: /* destroy the labels */
581: while (next) {
582: DMLabelLink tmp = next->next;
584: if (next->label == dm->depthLabel) dm->depthLabel = NULL;
585: if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
586: DMLabelDestroy(&next->label);
587: PetscFree(next);
588: next = tmp;
589: }
590: dm->labels = NULL;
591: return(0);
592: }
594: /*@C
595: DMDestroy - Destroys a vector packer or DM.
597: Collective on dm
599: Input Parameter:
600: . dm - the DM object to destroy
602: Level: developer
604: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
606: @*/
607: PetscErrorCode DMDestroy(DM *dm)
608: {
609: PetscInt cnt;
610: DMNamedVecLink nlink,nnext;
614: if (!*dm) return(0);
617: /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
618: DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
619: --((PetscObject)(*dm))->refct;
620: if (--cnt > 0) {*dm = NULL; return(0);}
621: if (((PetscObject)(*dm))->refct < 0) return(0);
622: ((PetscObject)(*dm))->refct = 0;
624: DMClearGlobalVectors(*dm);
625: DMClearLocalVectors(*dm);
627: nnext=(*dm)->namedglobal;
628: (*dm)->namedglobal = NULL;
629: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
630: nnext = nlink->next;
631: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
632: PetscFree(nlink->name);
633: VecDestroy(&nlink->X);
634: PetscFree(nlink);
635: }
636: nnext=(*dm)->namedlocal;
637: (*dm)->namedlocal = NULL;
638: for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
639: nnext = nlink->next;
640: if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
641: PetscFree(nlink->name);
642: VecDestroy(&nlink->X);
643: PetscFree(nlink);
644: }
646: /* Destroy the list of hooks */
647: {
648: DMCoarsenHookLink link,next;
649: for (link=(*dm)->coarsenhook; link; link=next) {
650: next = link->next;
651: PetscFree(link);
652: }
653: (*dm)->coarsenhook = NULL;
654: }
655: {
656: DMRefineHookLink link,next;
657: for (link=(*dm)->refinehook; link; link=next) {
658: next = link->next;
659: PetscFree(link);
660: }
661: (*dm)->refinehook = NULL;
662: }
663: {
664: DMSubDomainHookLink link,next;
665: for (link=(*dm)->subdomainhook; link; link=next) {
666: next = link->next;
667: PetscFree(link);
668: }
669: (*dm)->subdomainhook = NULL;
670: }
671: {
672: DMGlobalToLocalHookLink link,next;
673: for (link=(*dm)->gtolhook; link; link=next) {
674: next = link->next;
675: PetscFree(link);
676: }
677: (*dm)->gtolhook = NULL;
678: }
679: {
680: DMLocalToGlobalHookLink link,next;
681: for (link=(*dm)->ltoghook; link; link=next) {
682: next = link->next;
683: PetscFree(link);
684: }
685: (*dm)->ltoghook = NULL;
686: }
687: /* Destroy the work arrays */
688: {
689: DMWorkLink link,next;
690: if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
691: for (link=(*dm)->workin; link; link=next) {
692: next = link->next;
693: PetscFree(link->mem);
694: PetscFree(link);
695: }
696: (*dm)->workin = NULL;
697: }
698: /* destroy the labels */
699: DMDestroyLabelLinkList_Internal(*dm);
700: /* destroy the fields */
701: DMClearFields(*dm);
702: /* destroy the boundaries */
703: {
704: DMBoundary next = (*dm)->boundary;
705: while (next) {
706: DMBoundary b = next;
708: next = b->next;
709: PetscFree(b);
710: }
711: }
713: PetscObjectDestroy(&(*dm)->dmksp);
714: PetscObjectDestroy(&(*dm)->dmsnes);
715: PetscObjectDestroy(&(*dm)->dmts);
717: if ((*dm)->ctx && (*dm)->ctxdestroy) {
718: (*(*dm)->ctxdestroy)(&(*dm)->ctx);
719: }
720: MatFDColoringDestroy(&(*dm)->fd);
721: ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
722: PetscFree((*dm)->vectype);
723: PetscFree((*dm)->mattype);
725: PetscSectionDestroy(&(*dm)->localSection);
726: PetscSectionDestroy(&(*dm)->globalSection);
727: PetscLayoutDestroy(&(*dm)->map);
728: PetscSectionDestroy(&(*dm)->defaultConstraintSection);
729: MatDestroy(&(*dm)->defaultConstraintMat);
730: PetscSFDestroy(&(*dm)->sf);
731: PetscSFDestroy(&(*dm)->sectionSF);
732: if ((*dm)->useNatural) {
733: if ((*dm)->sfNatural) {
734: PetscSFDestroy(&(*dm)->sfNatural);
735: }
736: PetscObjectDereference((PetscObject) (*dm)->sfMigration);
737: }
738: if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
739: DMSetFineDM((*dm)->coarseMesh,NULL);
740: }
742: DMDestroy(&(*dm)->coarseMesh);
743: if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
744: DMSetCoarseDM((*dm)->fineMesh,NULL);
745: }
746: DMDestroy(&(*dm)->fineMesh);
747: DMFieldDestroy(&(*dm)->coordinateField);
748: DMDestroy(&(*dm)->coordinateDM);
749: VecDestroy(&(*dm)->coordinates);
750: VecDestroy(&(*dm)->coordinatesLocal);
751: PetscFree((*dm)->L);
752: PetscFree((*dm)->maxCell);
753: PetscFree((*dm)->bdtype);
754: if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
755: DMDestroy(&(*dm)->transformDM);
756: VecDestroy(&(*dm)->transform);
758: DMClearDS(*dm);
759: DMDestroy(&(*dm)->dmBC);
760: /* if memory was published with SAWs then destroy it */
761: PetscObjectSAWsViewOff((PetscObject)*dm);
763: if ((*dm)->ops->destroy) {
764: (*(*dm)->ops->destroy)(*dm);
765: }
766: DMMonitorCancel(*dm);
767: /* We do not destroy (*dm)->data here so that we can reference count backend objects */
768: PetscHeaderDestroy(dm);
769: return(0);
770: }
772: /*@
773: DMSetUp - sets up the data structures inside a DM object
775: Collective on dm
777: Input Parameter:
778: . dm - the DM object to setup
780: Level: developer
782: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
784: @*/
785: PetscErrorCode DMSetUp(DM dm)
786: {
791: if (dm->setupcalled) return(0);
792: if (dm->ops->setup) {
793: (*dm->ops->setup)(dm);
794: }
795: dm->setupcalled = PETSC_TRUE;
796: return(0);
797: }
799: /*@
800: DMSetFromOptions - sets parameters in a DM from the options database
802: Collective on dm
804: Input Parameter:
805: . dm - the DM object to set options for
807: Options Database:
808: + -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
809: . -dm_vec_type <type> - type of vector to create inside DM
810: . -dm_mat_type <type> - type of matrix to create inside DM
811: - -dm_is_coloring_type - <global or local>
813: DMPLEX Specific Checks
814: + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
815: . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
816: . -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()
817: . -dm_plex_check_geometry - Check that cells have positive volume - DMPlexCheckGeometry()
818: . -dm_plex_check_pointsf - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
819: . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
820: - -dm_plex_check_all - Perform all the checks above
822: Level: intermediate
824: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(),
825: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces(), DMPlexCheckGeometry(), DMPlexCheckPointSF(), DMPlexCheckInterfaceCones()
827: @*/
828: PetscErrorCode DMSetFromOptions(DM dm)
829: {
830: char typeName[256];
831: PetscBool flg;
836: dm->setfromoptionscalled = PETSC_TRUE;
837: if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
838: if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
839: PetscObjectOptionsBegin((PetscObject)dm);
840: PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
841: PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
842: if (flg) {
843: DMSetVecType(dm,typeName);
844: }
845: PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
846: if (flg) {
847: DMSetMatType(dm,typeName);
848: }
849: PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
850: if (dm->ops->setfromoptions) {
851: (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
852: }
853: /* process any options handlers added with PetscObjectAddOptionsHandler() */
854: PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
855: PetscOptionsEnd();
856: return(0);
857: }
859: /*@C
860: DMViewFromOptions - View from Options
862: Collective on DM
864: Input Parameters:
865: + dm - the DM object
866: . obj - Optional object
867: - name - command line option
869: Level: intermediate
870: .seealso: DM, DMView, PetscObjectViewFromOptions(), DMCreate()
871: @*/
872: PetscErrorCode DMViewFromOptions(DM dm,PetscObject obj,const char name[])
873: {
878: PetscObjectViewFromOptions((PetscObject)dm,obj,name);
879: return(0);
880: }
882: /*@C
883: DMView - Views a DM
885: Collective on dm
887: Input Parameter:
888: + dm - the DM object to view
889: - v - the viewer
891: Level: beginner
893: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
895: @*/
896: PetscErrorCode DMView(DM dm,PetscViewer v)
897: {
898: PetscErrorCode ierr;
899: PetscBool isbinary;
900: PetscMPIInt size;
901: PetscViewerFormat format;
905: if (!v) {
906: PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
907: }
909: /* Ideally, we would like to have this test on.
910: However, it currently breaks socket viz via GLVis.
911: During DMView(parallel_mesh,glvis_viewer), each
912: process opens a sequential ASCII socket to visualize
913: the local mesh, and PetscObjectView(dm,local_socket)
914: is internally called inside VecView_GLVis, incurring
915: in an error here */
917: PetscViewerCheckWritable(v);
919: PetscViewerGetFormat(v,&format);
920: MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
921: if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
922: PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
923: PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
924: if (isbinary) {
925: PetscInt classid = DM_FILE_CLASSID;
926: char type[256];
928: PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
929: PetscStrncpy(type,((PetscObject)dm)->type_name,256);
930: PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
931: }
932: if (dm->ops->view) {
933: (*dm->ops->view)(dm,v);
934: }
935: return(0);
936: }
938: /*@
939: DMCreateGlobalVector - Creates a global vector from a DM object
941: Collective on dm
943: Input Parameter:
944: . dm - the DM object
946: Output Parameter:
947: . vec - the global vector
949: Level: beginner
951: .seealso DMCreateLocalVector(), DMGetGlobalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
953: @*/
954: PetscErrorCode DMCreateGlobalVector(DM dm,Vec *vec)
955: {
961: if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
962: (*dm->ops->createglobalvector)(dm,vec);
963: if (PetscDefined(USE_DEBUG)) {
964: DM vdm;
966: VecGetDM(*vec,&vdm);
967: 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);
968: }
969: return(0);
970: }
972: /*@
973: DMCreateLocalVector - Creates a local vector from a DM object
975: Not Collective
977: Input Parameter:
978: . dm - the DM object
980: Output Parameter:
981: . vec - the local vector
983: Level: beginner
985: .seealso DMCreateGlobalVector(), DMGetLocalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
987: @*/
988: PetscErrorCode DMCreateLocalVector(DM dm,Vec *vec)
989: {
995: if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
996: (*dm->ops->createlocalvector)(dm,vec);
997: if (PetscDefined(USE_DEBUG)) {
998: DM vdm;
1000: VecGetDM(*vec,&vdm);
1001: 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);
1002: }
1003: return(0);
1004: }
1006: /*@
1007: DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
1009: Collective on dm
1011: Input Parameter:
1012: . dm - the DM that provides the mapping
1014: Output Parameter:
1015: . ltog - the mapping
1017: Level: intermediate
1019: Notes:
1020: This mapping can then be used by VecSetLocalToGlobalMapping() or
1021: MatSetLocalToGlobalMapping().
1023: .seealso: DMCreateLocalVector()
1024: @*/
1025: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1026: {
1027: PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1033: if (!dm->ltogmap) {
1034: PetscSection section, sectionGlobal;
1036: DMGetLocalSection(dm, §ion);
1037: if (section) {
1038: const PetscInt *cdofs;
1039: PetscInt *ltog;
1040: PetscInt pStart, pEnd, n, p, k, l;
1042: DMGetGlobalSection(dm, §ionGlobal);
1043: PetscSectionGetChart(section, &pStart, &pEnd);
1044: PetscSectionGetStorageSize(section, &n);
1045: PetscMalloc1(n, <og); /* We want the local+overlap size */
1046: for (p = pStart, l = 0; p < pEnd; ++p) {
1047: PetscInt bdof, cdof, dof, off, c, cind = 0;
1049: /* Should probably use constrained dofs */
1050: PetscSectionGetDof(section, p, &dof);
1051: PetscSectionGetConstraintDof(section, p, &cdof);
1052: PetscSectionGetConstraintIndices(section, p, &cdofs);
1053: PetscSectionGetOffset(sectionGlobal, p, &off);
1054: /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1055: bdof = cdof && (dof-cdof) ? 1 : dof;
1056: if (dof) {
1057: if (bs < 0) {bs = bdof;}
1058: else if (bs != bdof) {bs = 1;}
1059: }
1060: for (c = 0; c < dof; ++c, ++l) {
1061: if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1062: else ltog[l] = (off < 0 ? -(off+1) : off) + c;
1063: }
1064: }
1065: /* Must have same blocksize on all procs (some might have no points) */
1066: bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1067: PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1068: if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1069: else {bs = bsMinMax[0];}
1070: bs = bs < 0 ? 1 : bs;
1071: /* Must reduce indices by blocksize */
1072: if (bs > 1) {
1073: for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1074: n /= bs;
1075: }
1076: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1077: PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1078: } else {
1079: if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1080: (*dm->ops->getlocaltoglobalmapping)(dm);
1081: }
1082: }
1083: *ltog = dm->ltogmap;
1084: return(0);
1085: }
1087: /*@
1088: DMGetBlockSize - Gets the inherent block size associated with a DM
1090: Not Collective
1092: Input Parameter:
1093: . dm - the DM with block structure
1095: Output Parameter:
1096: . bs - the block size, 1 implies no exploitable block structure
1098: Level: intermediate
1100: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1101: @*/
1102: PetscErrorCode DMGetBlockSize(DM dm,PetscInt *bs)
1103: {
1107: if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1108: *bs = dm->bs;
1109: return(0);
1110: }
1112: /*@C
1113: DMCreateInterpolation - Gets interpolation matrix between two DM objects
1115: Collective on dmc
1117: Input Parameter:
1118: + dmc - the DM object
1119: - dmf - the second, finer DM object
1121: Output Parameter:
1122: + mat - the interpolation
1123: - vec - the scaling (optional)
1125: Level: developer
1127: Notes:
1128: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1129: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1131: For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1132: EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1135: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolationScale()
1137: @*/
1138: PetscErrorCode DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1139: {
1146: if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1147: PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1148: (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1149: PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1150: return(0);
1151: }
1153: /*@
1154: DMCreateInterpolationScale - Forms L = 1/(R*1) such that diag(L)*R preserves scale and is thus suitable for state (versus residual) restriction.
1156: Input Parameters:
1157: + dac - DM that defines a coarse mesh
1158: . daf - DM that defines a fine mesh
1159: - mat - the restriction (or interpolation operator) from fine to coarse
1161: Output Parameter:
1162: . scale - the scaled vector
1164: Level: developer
1166: .seealso: DMCreateInterpolation()
1168: @*/
1169: PetscErrorCode DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1170: {
1172: Vec fine;
1173: PetscScalar one = 1.0;
1176: DMCreateGlobalVector(daf,&fine);
1177: DMCreateGlobalVector(dac,scale);
1178: VecSet(fine,one);
1179: MatRestrict(mat,fine,*scale);
1180: VecDestroy(&fine);
1181: VecReciprocal(*scale);
1182: return(0);
1183: }
1185: /*@
1186: DMCreateRestriction - Gets restriction matrix between two DM objects
1188: Collective on dmc
1190: Input Parameter:
1191: + dmc - the DM object
1192: - dmf - the second, finer DM object
1194: Output Parameter:
1195: . mat - the restriction
1198: Level: developer
1200: Notes:
1201: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1202: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
1205: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()
1207: @*/
1208: PetscErrorCode DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1209: {
1216: if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1217: PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1218: (*dmc->ops->createrestriction)(dmc,dmf,mat);
1219: PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1220: return(0);
1221: }
1223: /*@
1224: DMCreateInjection - Gets injection matrix between two DM objects
1226: Collective on dac
1228: Input Parameter:
1229: + dac - the DM object
1230: - daf - the second, finer DM object
1232: Output Parameter:
1233: . mat - the injection
1235: Level: developer
1237: Notes:
1238: For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1239: DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
1241: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
1243: @*/
1244: PetscErrorCode DMCreateInjection(DM dac,DM daf,Mat *mat)
1245: {
1252: if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1253: PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1254: (*dac->ops->createinjection)(dac,daf,mat);
1255: PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1256: return(0);
1257: }
1259: /*@
1260: DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j
1262: Collective on dac
1264: Input Parameter:
1265: + dac - the DM object
1266: - daf - the second, finer DM object
1268: Output Parameter:
1269: . mat - the interpolation
1271: Level: developer
1273: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1274: @*/
1275: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1276: {
1283: if (!dac->ops->createmassmatrix) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMassMatrix",((PetscObject)dac)->type_name);
1284: (*dac->ops->createmassmatrix)(dac, daf, mat);
1285: return(0);
1286: }
1288: /*@
1289: DMCreateColoring - Gets coloring for a DM
1291: Collective on dm
1293: Input Parameter:
1294: + dm - the DM object
1295: - ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL
1297: Output Parameter:
1298: . coloring - the coloring
1300: Notes:
1301: Coloring of matrices can be computed directly from the sparse matrix nonzero structure via the MatColoring object or from the mesh from which the
1302: matrix comes from. In general using the mesh produces a more optimal coloring (fewer colors).
1304: This produces a coloring with the distance of 2, see MatSetColoringDistance() which can be used for efficiently computing Jacobians with MatFDColoringCreate()
1306: Level: developer
1308: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType(), MatColoring, MatFDColoringCreate()
1310: @*/
1311: PetscErrorCode DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1312: {
1318: if (!dm->ops->getcoloring) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateColoring",((PetscObject)dm)->type_name);
1319: (*dm->ops->getcoloring)(dm,ctype,coloring);
1320: return(0);
1321: }
1323: /*@
1324: DMCreateMatrix - Gets empty Jacobian for a DM
1326: Collective on dm
1328: Input Parameter:
1329: . dm - the DM object
1331: Output Parameter:
1332: . mat - the empty Jacobian
1334: Level: beginner
1337: Options Database Keys:
1338: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1340: Notes:
1341: This properly preallocates the number of nonzeros in the sparse matrix so you
1342: do not need to do it yourself.
1344: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1345: the nonzero pattern call DMSetMatrixPreallocateOnly()
1347: For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1348: internally by PETSc.
1350: For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1351: the indices for the global numbering for DMDAs which is complicated.
1353: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1355: @*/
1356: PetscErrorCode DMCreateMatrix(DM dm,Mat *mat)
1357: {
1363: if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1364: MatInitializePackage();
1365: PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1366: (*dm->ops->creatematrix)(dm,mat);
1367: if (PetscDefined(USE_DEBUG)) {
1368: DM mdm;
1370: MatGetDM(*mat,&mdm);
1371: 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);
1372: }
1373: /* Handle nullspace and near nullspace */
1374: if (dm->Nf) {
1375: MatNullSpace nullSpace;
1376: PetscInt Nf, f;
1378: DMGetNumFields(dm, &Nf);
1379: for (f = 0; f < Nf; ++f) {
1380: if (dm->nullspaceConstructors[f]) {
1381: (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1382: MatSetNullSpace(*mat, nullSpace);
1383: MatNullSpaceDestroy(&nullSpace);
1384: break;
1385: }
1386: }
1387: for (f = 0; f < Nf; ++f) {
1388: if (dm->nearnullspaceConstructors[f]) {
1389: (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1390: MatSetNearNullSpace(*mat, nullSpace);
1391: MatNullSpaceDestroy(&nullSpace);
1392: }
1393: }
1394: }
1395: PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1396: return(0);
1397: }
1399: /*@
1400: DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1401: preallocated but the nonzero structure and zero values will not be set.
1403: Logically Collective on dm
1405: Input Parameter:
1406: + dm - the DM
1407: - only - PETSC_TRUE if only want preallocation
1409: Level: developer
1411: Options Database Keys:
1412: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
1414: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1415: @*/
1416: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1417: {
1420: dm->prealloc_only = only;
1421: return(0);
1422: }
1424: /*@
1425: DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1426: but the array for values will not be allocated.
1428: Logically Collective on dm
1430: Input Parameter:
1431: + dm - the DM
1432: - only - PETSC_TRUE if only want matrix stucture
1434: Level: developer
1435: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1436: @*/
1437: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1438: {
1441: dm->structure_only = only;
1442: return(0);
1443: }
1445: /*@C
1446: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1448: Not Collective
1450: Input Parameters:
1451: + dm - the DM object
1452: . count - The minium size
1453: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1455: Output Parameter:
1456: . array - the work array
1458: Level: developer
1460: .seealso DMDestroy(), DMCreate()
1461: @*/
1462: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1463: {
1465: DMWorkLink link;
1466: PetscMPIInt dsize;
1471: if (dm->workin) {
1472: link = dm->workin;
1473: dm->workin = dm->workin->next;
1474: } else {
1475: PetscNewLog(dm,&link);
1476: }
1477: MPI_Type_size(dtype,&dsize);
1478: if (((size_t)dsize*count) > link->bytes) {
1479: PetscFree(link->mem);
1480: PetscMalloc(dsize*count,&link->mem);
1481: link->bytes = dsize*count;
1482: }
1483: link->next = dm->workout;
1484: dm->workout = link;
1485: #if defined(PETSC_HAVE_VALGRIND)
1486: VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1487: VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1488: #endif
1489: *(void**)mem = link->mem;
1490: return(0);
1491: }
1493: /*@C
1494: DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1496: Not Collective
1498: Input Parameters:
1499: + dm - the DM object
1500: . count - The minium size
1501: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1503: Output Parameter:
1504: . array - the work array
1506: Level: developer
1508: Developer Notes:
1509: count and dtype are ignored, they are only needed for DMGetWorkArray()
1510: .seealso DMDestroy(), DMCreate()
1511: @*/
1512: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1513: {
1514: DMWorkLink *p,link;
1519: for (p=&dm->workout; (link=*p); p=&link->next) {
1520: if (link->mem == *(void**)mem) {
1521: *p = link->next;
1522: link->next = dm->workin;
1523: dm->workin = link;
1524: *(void**)mem = NULL;
1525: return(0);
1526: }
1527: }
1528: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1529: }
1531: /*@C
1532: DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field
1534: Logically collective on DM
1536: Input Parameters:
1537: + dm - The DM
1538: . field - The field number for the nullspace
1539: - nullsp - A callback to create the nullspace
1541: Notes:
1542: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1543: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1544: $ dm - The present DM
1545: $ origField - The field number given above, in the original DM
1546: $ field - The field number in dm
1547: $ nullSpace - The nullspace for the given field
1549: This function is currently not available from Fortran.
1551: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1552: */
1553: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1554: {
1557: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1558: dm->nullspaceConstructors[field] = nullsp;
1559: return(0);
1560: }
1562: /*@C
1563: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL
1565: Not collective
1567: Input Parameters:
1568: + dm - The DM
1569: - field - The field number for the nullspace
1571: Output Parameter:
1572: . nullsp - A callback to create the nullspace
1574: Notes:
1575: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1576: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1577: $ dm - The present DM
1578: $ origField - The field number given above, in the original DM
1579: $ field - The field number in dm
1580: $ nullSpace - The nullspace for the given field
1582: This function is currently not available from Fortran.
1584: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1585: */
1586: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1587: {
1591: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1592: *nullsp = dm->nullspaceConstructors[field];
1593: return(0);
1594: }
1596: /*@C
1597: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field
1599: Logically collective on DM
1601: Input Parameters:
1602: + dm - The DM
1603: . field - The field number for the nullspace
1604: - nullsp - A callback to create the near-nullspace
1606: Notes:
1607: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1608: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1609: $ dm - The present DM
1610: $ origField - The field number given above, in the original DM
1611: $ field - The field number in dm
1612: $ nullSpace - The nullspace for the given field
1614: This function is currently not available from Fortran.
1616: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1617: */
1618: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1619: {
1622: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1623: dm->nearnullspaceConstructors[field] = nullsp;
1624: return(0);
1625: }
1627: /*@C
1628: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL
1630: Not collective
1632: Input Parameters:
1633: + dm - The DM
1634: - field - The field number for the nullspace
1636: Output Parameter:
1637: . nullsp - A callback to create the near-nullspace
1639: Notes:
1640: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1641: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1642: $ dm - The present DM
1643: $ origField - The field number given above, in the original DM
1644: $ field - The field number in dm
1645: $ nullSpace - The nullspace for the given field
1647: This function is currently not available from Fortran.
1649: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1650: */
1651: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1652: {
1656: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1657: *nullsp = dm->nearnullspaceConstructors[field];
1658: return(0);
1659: }
1661: /*@C
1662: DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1664: Not collective
1666: Input Parameter:
1667: . dm - the DM object
1669: Output Parameters:
1670: + numFields - The number of fields (or NULL if not requested)
1671: . fieldNames - The name for each field (or NULL if not requested)
1672: - fields - The global indices for each field (or NULL if not requested)
1674: Level: intermediate
1676: Notes:
1677: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1678: PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1679: PetscFree().
1681: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1682: @*/
1683: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1684: {
1685: PetscSection section, sectionGlobal;
1690: if (numFields) {
1692: *numFields = 0;
1693: }
1694: if (fieldNames) {
1696: *fieldNames = NULL;
1697: }
1698: if (fields) {
1700: *fields = NULL;
1701: }
1702: DMGetLocalSection(dm, §ion);
1703: if (section) {
1704: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1705: PetscInt nF, f, pStart, pEnd, p;
1707: DMGetGlobalSection(dm, §ionGlobal);
1708: PetscSectionGetNumFields(section, &nF);
1709: PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1710: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1711: for (f = 0; f < nF; ++f) {
1712: fieldSizes[f] = 0;
1713: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1714: }
1715: for (p = pStart; p < pEnd; ++p) {
1716: PetscInt gdof;
1718: PetscSectionGetDof(sectionGlobal, p, &gdof);
1719: if (gdof > 0) {
1720: for (f = 0; f < nF; ++f) {
1721: PetscInt fdof, fcdof, fpdof;
1723: PetscSectionGetFieldDof(section, p, f, &fdof);
1724: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1725: fpdof = fdof-fcdof;
1726: if (fpdof && fpdof != fieldNc[f]) {
1727: /* Layout does not admit a pointwise block size */
1728: fieldNc[f] = 1;
1729: }
1730: fieldSizes[f] += fpdof;
1731: }
1732: }
1733: }
1734: for (f = 0; f < nF; ++f) {
1735: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1736: fieldSizes[f] = 0;
1737: }
1738: for (p = pStart; p < pEnd; ++p) {
1739: PetscInt gdof, goff;
1741: PetscSectionGetDof(sectionGlobal, p, &gdof);
1742: if (gdof > 0) {
1743: PetscSectionGetOffset(sectionGlobal, p, &goff);
1744: for (f = 0; f < nF; ++f) {
1745: PetscInt fdof, fcdof, fc;
1747: PetscSectionGetFieldDof(section, p, f, &fdof);
1748: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1749: for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1750: fieldIndices[f][fieldSizes[f]] = goff++;
1751: }
1752: }
1753: }
1754: }
1755: if (numFields) *numFields = nF;
1756: if (fieldNames) {
1757: PetscMalloc1(nF, fieldNames);
1758: for (f = 0; f < nF; ++f) {
1759: const char *fieldName;
1761: PetscSectionGetFieldName(section, f, &fieldName);
1762: PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1763: }
1764: }
1765: if (fields) {
1766: PetscMalloc1(nF, fields);
1767: for (f = 0; f < nF; ++f) {
1768: PetscInt bs, in[2], out[2];
1770: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1771: in[0] = -fieldNc[f];
1772: in[1] = fieldNc[f];
1773: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1774: bs = (-out[0] == out[1]) ? out[1] : 1;
1775: ISSetBlockSize((*fields)[f], bs);
1776: }
1777: }
1778: PetscFree3(fieldSizes,fieldNc,fieldIndices);
1779: } else if (dm->ops->createfieldis) {
1780: (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1781: }
1782: return(0);
1783: }
1786: /*@C
1787: DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1788: corresponding to different fields: each IS contains the global indices of the dofs of the
1789: corresponding field. The optional list of DMs define the DM for each subproblem.
1790: Generalizes DMCreateFieldIS().
1792: Not collective
1794: Input Parameter:
1795: . dm - the DM object
1797: Output Parameters:
1798: + len - The number of subproblems in the field decomposition (or NULL if not requested)
1799: . namelist - The name for each field (or NULL if not requested)
1800: . islist - The global indices for each field (or NULL if not requested)
1801: - dmlist - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1803: Level: intermediate
1805: Notes:
1806: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1807: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1808: and all of the arrays should be freed with PetscFree().
1810: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1811: @*/
1812: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1813: {
1818: if (len) {
1820: *len = 0;
1821: }
1822: if (namelist) {
1824: *namelist = NULL;
1825: }
1826: if (islist) {
1828: *islist = NULL;
1829: }
1830: if (dmlist) {
1832: *dmlist = NULL;
1833: }
1834: /*
1835: Is it a good idea to apply the following check across all impls?
1836: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1837: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1838: */
1839: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1840: if (!dm->ops->createfielddecomposition) {
1841: PetscSection section;
1842: PetscInt numFields, f;
1844: DMGetLocalSection(dm, §ion);
1845: if (section) {PetscSectionGetNumFields(section, &numFields);}
1846: if (section && numFields && dm->ops->createsubdm) {
1847: if (len) *len = numFields;
1848: if (namelist) {PetscMalloc1(numFields,namelist);}
1849: if (islist) {PetscMalloc1(numFields,islist);}
1850: if (dmlist) {PetscMalloc1(numFields,dmlist);}
1851: for (f = 0; f < numFields; ++f) {
1852: const char *fieldName;
1854: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1855: if (namelist) {
1856: PetscSectionGetFieldName(section, f, &fieldName);
1857: PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1858: }
1859: }
1860: } else {
1861: DMCreateFieldIS(dm, len, namelist, islist);
1862: /* By default there are no DMs associated with subproblems. */
1863: if (dmlist) *dmlist = NULL;
1864: }
1865: } else {
1866: (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1867: }
1868: return(0);
1869: }
1871: /*@
1872: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1873: The fields are defined by DMCreateFieldIS().
1875: Not collective
1877: Input Parameters:
1878: + dm - The DM object
1879: . numFields - The number of fields in this subproblem
1880: - fields - The field numbers of the selected fields
1882: Output Parameters:
1883: + is - The global indices for the subproblem
1884: - subdm - The DM for the subproblem
1886: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1888: Level: intermediate
1890: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1891: @*/
1892: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1893: {
1901: if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
1902: (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1903: return(0);
1904: }
1906: /*@C
1907: DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.
1909: Not collective
1911: Input Parameter:
1912: + dms - The DM objects
1913: - len - The number of DMs
1915: Output Parameters:
1916: + is - The global indices for the subproblem, or NULL
1917: - superdm - The DM for the superproblem
1919: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1921: Level: intermediate
1923: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1924: @*/
1925: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1926: {
1927: PetscInt i;
1935: if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1936: if (len) {
1937: DM dm = dms[0];
1938: if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1939: (*dm->ops->createsuperdm)(dms, len, is, superdm);
1940: }
1941: return(0);
1942: }
1945: /*@C
1946: DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1947: corresponding to restrictions to pairs nested subdomains: each IS contains the global
1948: indices of the dofs of the corresponding subdomains. The inner subdomains conceptually
1949: define a nonoverlapping covering, while outer subdomains can overlap.
1950: The optional list of DMs define the DM for each subproblem.
1952: Not collective
1954: Input Parameter:
1955: . dm - the DM object
1957: Output Parameters:
1958: + len - The number of subproblems in the domain decomposition (or NULL if not requested)
1959: . namelist - The name for each subdomain (or NULL if not requested)
1960: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1961: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1962: - dmlist - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1964: Level: intermediate
1966: Notes:
1967: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1968: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1969: and all of the arrays should be freed with PetscFree().
1971: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1972: @*/
1973: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1974: {
1975: PetscErrorCode ierr;
1976: DMSubDomainHookLink link;
1977: PetscInt i,l;
1986: /*
1987: Is it a good idea to apply the following check across all impls?
1988: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1989: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1990: */
1991: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1992: if (dm->ops->createdomaindecomposition) {
1993: (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1994: /* copy subdomain hooks and context over to the subdomain DMs */
1995: if (dmlist && *dmlist) {
1996: for (i = 0; i < l; i++) {
1997: for (link=dm->subdomainhook; link; link=link->next) {
1998: if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1999: }
2000: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2001: }
2002: }
2003: if (len) *len = l;
2004: }
2005: return(0);
2006: }
2009: /*@C
2010: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
2012: Not collective
2014: Input Parameters:
2015: + dm - the DM object
2016: . n - the number of subdomain scatters
2017: - subdms - the local subdomains
2019: Output Parameters:
2020: + n - the number of scatters returned
2021: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2022: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2023: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2025: Notes:
2026: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2027: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2028: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2029: solution and residual data.
2031: Level: developer
2033: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2034: @*/
2035: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2036: {
2042: if (!dm->ops->createddscatters) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateDomainDecompositionScatters",((PetscObject)dm)->type_name);
2043: (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2044: return(0);
2045: }
2047: /*@
2048: DMRefine - Refines a DM object
2050: Collective on dm
2052: Input Parameter:
2053: + dm - the DM object
2054: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2056: Output Parameter:
2057: . dmf - the refined DM, or NULL
2059: Options Database Keys:
2060: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2062: Note: If no refinement was done, the return value is NULL
2064: Level: developer
2066: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2067: @*/
2068: PetscErrorCode DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2069: {
2070: PetscErrorCode ierr;
2071: DMRefineHookLink link;
2075: if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2076: PetscLogEventBegin(DM_Refine,dm,0,0,0);
2077: (*dm->ops->refine)(dm,comm,dmf);
2078: if (*dmf) {
2079: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2081: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);
2083: (*dmf)->ctx = dm->ctx;
2084: (*dmf)->leveldown = dm->leveldown;
2085: (*dmf)->levelup = dm->levelup + 1;
2087: DMSetMatType(*dmf,dm->mattype);
2088: for (link=dm->refinehook; link; link=link->next) {
2089: if (link->refinehook) {
2090: (*link->refinehook)(dm,*dmf,link->ctx);
2091: }
2092: }
2093: }
2094: PetscLogEventEnd(DM_Refine,dm,0,0,0);
2095: return(0);
2096: }
2098: /*@C
2099: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2101: Logically Collective
2103: Input Arguments:
2104: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2105: . refinehook - function to run when setting up a coarser level
2106: . interphook - function to run to update data on finer levels (once per SNESSolve())
2107: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2109: Calling sequence of refinehook:
2110: $ refinehook(DM coarse,DM fine,void *ctx);
2112: + coarse - coarse level DM
2113: . fine - fine level DM to interpolate problem to
2114: - ctx - optional user-defined function context
2116: Calling sequence for interphook:
2117: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2119: + coarse - coarse level DM
2120: . interp - matrix interpolating a coarse-level solution to the finer grid
2121: . fine - fine level DM to update
2122: - ctx - optional user-defined function context
2124: Level: advanced
2126: Notes:
2127: This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
2129: If this function is called multiple times, the hooks will be run in the order they are added.
2131: This function is currently not available from Fortran.
2133: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2134: @*/
2135: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2136: {
2137: PetscErrorCode ierr;
2138: DMRefineHookLink link,*p;
2142: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2143: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2144: }
2145: PetscNew(&link);
2146: link->refinehook = refinehook;
2147: link->interphook = interphook;
2148: link->ctx = ctx;
2149: link->next = NULL;
2150: *p = link;
2151: return(0);
2152: }
2154: /*@C
2155: DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
2157: Logically Collective
2159: Input Arguments:
2160: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2161: . refinehook - function to run when setting up a coarser level
2162: . interphook - function to run to update data on finer levels (once per SNESSolve())
2163: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2165: Level: advanced
2167: Notes:
2168: This function does nothing if the hook is not in the list.
2170: This function is currently not available from Fortran.
2172: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2173: @*/
2174: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2175: {
2176: PetscErrorCode ierr;
2177: DMRefineHookLink link,*p;
2181: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2182: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2183: link = *p;
2184: *p = link->next;
2185: PetscFree(link);
2186: break;
2187: }
2188: }
2189: return(0);
2190: }
2192: /*@
2193: DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
2195: Collective if any hooks are
2197: Input Arguments:
2198: + coarse - coarser DM to use as a base
2199: . interp - interpolation matrix, apply using MatInterpolate()
2200: - fine - finer DM to update
2202: Level: developer
2204: .seealso: DMRefineHookAdd(), MatInterpolate()
2205: @*/
2206: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2207: {
2208: PetscErrorCode ierr;
2209: DMRefineHookLink link;
2212: for (link=fine->refinehook; link; link=link->next) {
2213: if (link->interphook) {
2214: (*link->interphook)(coarse,interp,fine,link->ctx);
2215: }
2216: }
2217: return(0);
2218: }
2220: /*@
2221: DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2223: Collective on DM
2225: Input Arguments:
2226: + coarse - coarse DM
2227: . fine - fine DM
2228: . interp - (optional) the matrix computed by DMCreateInterpolation(). Implementations may not need this, but if it
2229: is available it can avoid some recomputation. If it is provided, MatInterpolate() will be used if
2230: the coarse DM does not have a specialized implementation.
2231: - coarseSol - solution on the coarse mesh
2233: Output Arguments:
2234: . fineSol - the interpolation of coarseSol to the fine mesh
2236: Level: developer
2238: Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2239: map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2240: out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2241: slope-limiting reconstruction.
2243: .seealso DMInterpolate(), DMCreateInterpolation()
2244: @*/
2245: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2246: {
2247: PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;
2257: PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2258: if (interpsol) {
2259: (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2260: } else if (interp) {
2261: MatInterpolate(interp, coarseSol, fineSol);
2262: } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2263: return(0);
2264: }
2266: /*@
2267: DMGetRefineLevel - Gets the number of refinements that have generated this DM.
2269: Not Collective
2271: Input Parameter:
2272: . dm - the DM object
2274: Output Parameter:
2275: . level - number of refinements
2277: Level: developer
2279: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2281: @*/
2282: PetscErrorCode DMGetRefineLevel(DM dm,PetscInt *level)
2283: {
2286: *level = dm->levelup;
2287: return(0);
2288: }
2290: /*@
2291: DMSetRefineLevel - Sets the number of refinements that have generated this DM.
2293: Not Collective
2295: Input Parameter:
2296: + dm - the DM object
2297: - level - number of refinements
2299: Level: advanced
2301: Notes:
2302: This value is used by PCMG to determine how many multigrid levels to use
2304: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2306: @*/
2307: PetscErrorCode DMSetRefineLevel(DM dm,PetscInt level)
2308: {
2311: dm->levelup = level;
2312: return(0);
2313: }
2315: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2316: {
2320: *tdm = dm->transformDM;
2321: return(0);
2322: }
2324: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2325: {
2329: *tv = dm->transform;
2330: return(0);
2331: }
2333: /*@
2334: DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors
2336: Input Parameter:
2337: . dm - The DM
2339: Output Parameter:
2340: . flg - PETSC_TRUE if a basis transformation should be done
2342: Level: developer
2344: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2345: @*/
2346: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2347: {
2348: Vec tv;
2354: DMGetBasisTransformVec_Internal(dm, &tv);
2355: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2356: return(0);
2357: }
2359: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2360: {
2361: PetscSection s, ts;
2362: PetscScalar *ta;
2363: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2367: DMGetCoordinateDim(dm, &cdim);
2368: DMGetLocalSection(dm, &s);
2369: PetscSectionGetChart(s, &pStart, &pEnd);
2370: PetscSectionGetNumFields(s, &Nf);
2371: DMClone(dm, &dm->transformDM);
2372: DMGetLocalSection(dm->transformDM, &ts);
2373: PetscSectionSetNumFields(ts, Nf);
2374: PetscSectionSetChart(ts, pStart, pEnd);
2375: for (f = 0; f < Nf; ++f) {
2376: PetscSectionGetFieldComponents(s, f, &Nc);
2377: /* We could start to label fields by their transformation properties */
2378: if (Nc != cdim) continue;
2379: for (p = pStart; p < pEnd; ++p) {
2380: PetscSectionGetFieldDof(s, p, f, &dof);
2381: if (!dof) continue;
2382: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2383: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2384: }
2385: }
2386: PetscSectionSetUp(ts);
2387: DMCreateLocalVector(dm->transformDM, &dm->transform);
2388: VecGetArray(dm->transform, &ta);
2389: for (p = pStart; p < pEnd; ++p) {
2390: for (f = 0; f < Nf; ++f) {
2391: PetscSectionGetFieldDof(ts, p, f, &dof);
2392: if (dof) {
2393: PetscReal x[3] = {0.0, 0.0, 0.0};
2394: PetscScalar *tva;
2395: const PetscScalar *A;
2397: /* TODO Get quadrature point for this dual basis vector for coordinate */
2398: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2399: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2400: PetscArraycpy(tva, A, PetscSqr(cdim));
2401: }
2402: }
2403: }
2404: VecRestoreArray(dm->transform, &ta);
2405: return(0);
2406: }
2408: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2409: {
2415: newdm->transformCtx = dm->transformCtx;
2416: newdm->transformSetUp = dm->transformSetUp;
2417: newdm->transformDestroy = NULL;
2418: newdm->transformGetMatrix = dm->transformGetMatrix;
2419: if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2420: return(0);
2421: }
2423: /*@C
2424: DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
2426: Logically Collective
2428: Input Arguments:
2429: + dm - the DM
2430: . beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2431: . endhook - function to run after DMGlobalToLocalEnd() has completed
2432: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2434: Calling sequence for beginhook:
2435: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2437: + dm - global DM
2438: . g - global vector
2439: . mode - mode
2440: . l - local vector
2441: - ctx - optional user-defined function context
2444: Calling sequence for endhook:
2445: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2447: + global - global DM
2448: - ctx - optional user-defined function context
2450: Level: advanced
2452: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2453: @*/
2454: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2455: {
2456: PetscErrorCode ierr;
2457: DMGlobalToLocalHookLink link,*p;
2461: for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2462: PetscNew(&link);
2463: link->beginhook = beginhook;
2464: link->endhook = endhook;
2465: link->ctx = ctx;
2466: link->next = NULL;
2467: *p = link;
2468: return(0);
2469: }
2471: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2472: {
2473: Mat cMat;
2474: Vec cVec;
2475: PetscSection section, cSec;
2476: PetscInt pStart, pEnd, p, dof;
2481: DMGetDefaultConstraints(dm,&cSec,&cMat);
2482: if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2483: PetscInt nRows;
2485: MatGetSize(cMat,&nRows,NULL);
2486: if (nRows <= 0) return(0);
2487: DMGetLocalSection(dm,§ion);
2488: MatCreateVecs(cMat,NULL,&cVec);
2489: MatMult(cMat,l,cVec);
2490: PetscSectionGetChart(cSec,&pStart,&pEnd);
2491: for (p = pStart; p < pEnd; p++) {
2492: PetscSectionGetDof(cSec,p,&dof);
2493: if (dof) {
2494: PetscScalar *vals;
2495: VecGetValuesSection(cVec,cSec,p,&vals);
2496: VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2497: }
2498: }
2499: VecDestroy(&cVec);
2500: }
2501: return(0);
2502: }
2504: /*@
2505: DMGlobalToLocal - update local vectors from global vector
2507: Neighbor-wise Collective on dm
2509: Input Parameters:
2510: + dm - the DM object
2511: . g - the global vector
2512: . mode - INSERT_VALUES or ADD_VALUES
2513: - l - the local vector
2515: Notes:
2516: The communication involved in this update can be overlapped with computation by using
2517: DMGlobalToLocalBegin() and DMGlobalToLocalEnd().
2519: Level: beginner
2521: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2523: @*/
2524: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2525: {
2529: DMGlobalToLocalBegin(dm,g,mode,l);
2530: DMGlobalToLocalEnd(dm,g,mode,l);
2531: return(0);
2532: }
2534: /*@
2535: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2537: Neighbor-wise Collective on dm
2539: Input Parameters:
2540: + dm - the DM object
2541: . g - the global vector
2542: . mode - INSERT_VALUES or ADD_VALUES
2543: - l - the local vector
2545: Level: intermediate
2547: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2549: @*/
2550: PetscErrorCode DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2551: {
2552: PetscSF sf;
2553: PetscErrorCode ierr;
2554: DMGlobalToLocalHookLink link;
2559: for (link=dm->gtolhook; link; link=link->next) {
2560: if (link->beginhook) {
2561: (*link->beginhook)(dm,g,mode,l,link->ctx);
2562: }
2563: }
2564: DMGetSectionSF(dm, &sf);
2565: if (sf) {
2566: const PetscScalar *gArray;
2567: PetscScalar *lArray;
2568: PetscMemType lmtype,gmtype;
2570: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2571: VecGetArrayAndMemType(l, &lArray, &lmtype);
2572: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2573: PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2574: VecRestoreArrayAndMemType(l, &lArray);
2575: VecRestoreArrayReadAndMemType(g, &gArray);
2576: } else {
2577: if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2578: (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2579: }
2580: return(0);
2581: }
2583: /*@
2584: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2586: Neighbor-wise Collective on dm
2588: Input Parameters:
2589: + dm - the DM object
2590: . g - the global vector
2591: . mode - INSERT_VALUES or ADD_VALUES
2592: - l - the local vector
2594: Level: intermediate
2596: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2598: @*/
2599: PetscErrorCode DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2600: {
2601: PetscSF sf;
2602: PetscErrorCode ierr;
2603: const PetscScalar *gArray;
2604: PetscScalar *lArray;
2605: PetscBool transform;
2606: DMGlobalToLocalHookLink link;
2607: PetscMemType lmtype,gmtype;
2611: DMGetSectionSF(dm, &sf);
2612: DMHasBasisTransform(dm, &transform);
2613: if (sf) {
2614: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2616: VecGetArrayAndMemType(l, &lArray, &lmtype);
2617: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2618: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2619: VecRestoreArrayAndMemType(l, &lArray);
2620: VecRestoreArrayReadAndMemType(g, &gArray);
2621: if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2622: } else {
2623: if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2624: (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2625: }
2626: DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2627: for (link=dm->gtolhook; link; link=link->next) {
2628: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2629: }
2630: return(0);
2631: }
2633: /*@C
2634: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2636: Logically Collective
2638: Input Arguments:
2639: + dm - the DM
2640: . beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2641: . endhook - function to run after DMLocalToGlobalEnd() has completed
2642: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2644: Calling sequence for beginhook:
2645: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2647: + dm - global DM
2648: . l - local vector
2649: . mode - mode
2650: . g - global vector
2651: - ctx - optional user-defined function context
2654: Calling sequence for endhook:
2655: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2657: + global - global DM
2658: . l - local vector
2659: . mode - mode
2660: . g - global vector
2661: - ctx - optional user-defined function context
2663: Level: advanced
2665: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2666: @*/
2667: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2668: {
2669: PetscErrorCode ierr;
2670: DMLocalToGlobalHookLink link,*p;
2674: for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2675: PetscNew(&link);
2676: link->beginhook = beginhook;
2677: link->endhook = endhook;
2678: link->ctx = ctx;
2679: link->next = NULL;
2680: *p = link;
2681: return(0);
2682: }
2684: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2685: {
2686: Mat cMat;
2687: Vec cVec;
2688: PetscSection section, cSec;
2689: PetscInt pStart, pEnd, p, dof;
2694: DMGetDefaultConstraints(dm,&cSec,&cMat);
2695: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2696: PetscInt nRows;
2698: MatGetSize(cMat,&nRows,NULL);
2699: if (nRows <= 0) return(0);
2700: DMGetLocalSection(dm,§ion);
2701: MatCreateVecs(cMat,NULL,&cVec);
2702: PetscSectionGetChart(cSec,&pStart,&pEnd);
2703: for (p = pStart; p < pEnd; p++) {
2704: PetscSectionGetDof(cSec,p,&dof);
2705: if (dof) {
2706: PetscInt d;
2707: PetscScalar *vals;
2708: VecGetValuesSection(l,section,p,&vals);
2709: VecSetValuesSection(cVec,cSec,p,vals,mode);
2710: /* for this to be the true transpose, we have to zero the values that
2711: * we just extracted */
2712: for (d = 0; d < dof; d++) {
2713: vals[d] = 0.;
2714: }
2715: }
2716: }
2717: MatMultTransposeAdd(cMat,cVec,l,l);
2718: VecDestroy(&cVec);
2719: }
2720: return(0);
2721: }
2722: /*@
2723: DMLocalToGlobal - updates global vectors from local vectors
2725: Neighbor-wise Collective on dm
2727: Input Parameters:
2728: + dm - the DM object
2729: . l - the local vector
2730: . 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.
2731: - g - the global vector
2733: Notes:
2734: The communication involved in this update can be overlapped with computation by using
2735: DMLocalToGlobalBegin() and DMLocalToGlobalEnd().
2737: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2738: INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.
2740: Level: beginner
2742: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2744: @*/
2745: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2746: {
2750: DMLocalToGlobalBegin(dm,l,mode,g);
2751: DMLocalToGlobalEnd(dm,l,mode,g);
2752: return(0);
2753: }
2755: /*@
2756: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2758: Neighbor-wise Collective on dm
2760: Input Parameters:
2761: + dm - the DM object
2762: . l - the local vector
2763: . 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.
2764: - g - the global vector
2766: Notes:
2767: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2768: INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2770: Level: intermediate
2772: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2774: @*/
2775: PetscErrorCode DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2776: {
2777: PetscSF sf;
2778: PetscSection s, gs;
2779: DMLocalToGlobalHookLink link;
2780: Vec tmpl;
2781: const PetscScalar *lArray;
2782: PetscScalar *gArray;
2783: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2784: PetscErrorCode ierr;
2785: PetscMemType lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;
2789: for (link=dm->ltoghook; link; link=link->next) {
2790: if (link->beginhook) {
2791: (*link->beginhook)(dm,l,mode,g,link->ctx);
2792: }
2793: }
2794: DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2795: DMGetSectionSF(dm, &sf);
2796: DMGetLocalSection(dm, &s);
2797: switch (mode) {
2798: case INSERT_VALUES:
2799: case INSERT_ALL_VALUES:
2800: case INSERT_BC_VALUES:
2801: isInsert = PETSC_TRUE; break;
2802: case ADD_VALUES:
2803: case ADD_ALL_VALUES:
2804: case ADD_BC_VALUES:
2805: isInsert = PETSC_FALSE; break;
2806: default:
2807: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2808: }
2809: if ((sf && !isInsert) || (s && isInsert)) {
2810: DMHasBasisTransform(dm, &transform);
2811: if (transform) {
2812: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2813: VecCopy(l, tmpl);
2814: DMPlexLocalToGlobalBasis(dm, tmpl);
2815: VecGetArrayRead(tmpl, &lArray);
2816: } else if (isInsert) {
2817: VecGetArrayRead(l, &lArray);
2818: } else {
2819: VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2820: l_inplace = PETSC_TRUE;
2821: }
2822: if (s && isInsert) {
2823: VecGetArray(g, &gArray);
2824: } else {
2825: VecGetArrayAndMemType(g, &gArray, &gmtype);
2826: g_inplace = PETSC_TRUE;
2827: }
2828: if (sf && !isInsert) {
2829: PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2830: } else if (s && isInsert) {
2831: PetscInt gStart, pStart, pEnd, p;
2833: DMGetGlobalSection(dm, &gs);
2834: PetscSectionGetChart(s, &pStart, &pEnd);
2835: VecGetOwnershipRange(g, &gStart, NULL);
2836: for (p = pStart; p < pEnd; ++p) {
2837: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2839: PetscSectionGetDof(s, p, &dof);
2840: PetscSectionGetDof(gs, p, &gdof);
2841: PetscSectionGetConstraintDof(s, p, &cdof);
2842: PetscSectionGetConstraintDof(gs, p, &gcdof);
2843: PetscSectionGetOffset(s, p, &off);
2844: PetscSectionGetOffset(gs, p, &goff);
2845: /* Ignore off-process data and points with no global data */
2846: if (!gdof || goff < 0) continue;
2847: 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);
2848: /* If no constraints are enforced in the global vector */
2849: if (!gcdof) {
2850: for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2851: /* If constraints are enforced in the global vector */
2852: } else if (cdof == gcdof) {
2853: const PetscInt *cdofs;
2854: PetscInt cind = 0;
2856: PetscSectionGetConstraintIndices(s, p, &cdofs);
2857: for (d = 0, e = 0; d < dof; ++d) {
2858: if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2859: gArray[goff-gStart+e++] = lArray[off+d];
2860: }
2861: } 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);
2862: }
2863: }
2864: if (g_inplace) {
2865: VecRestoreArrayAndMemType(g, &gArray);
2866: } else {
2867: VecRestoreArray(g, &gArray);
2868: }
2869: if (transform) {
2870: VecRestoreArrayRead(tmpl, &lArray);
2871: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2872: } else if (l_inplace) {
2873: VecRestoreArrayReadAndMemType(l, &lArray);
2874: } else {
2875: VecRestoreArrayRead(l, &lArray);
2876: }
2877: } else {
2878: if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2879: (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2880: }
2881: return(0);
2882: }
2884: /*@
2885: DMLocalToGlobalEnd - updates global vectors from local vectors
2887: Neighbor-wise Collective on dm
2889: Input Parameters:
2890: + dm - the DM object
2891: . l - the local vector
2892: . mode - INSERT_VALUES or ADD_VALUES
2893: - g - the global vector
2895: Level: intermediate
2897: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2899: @*/
2900: PetscErrorCode DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2901: {
2902: PetscSF sf;
2903: PetscSection s;
2904: DMLocalToGlobalHookLink link;
2905: PetscBool isInsert, transform;
2906: PetscErrorCode ierr;
2910: DMGetSectionSF(dm, &sf);
2911: DMGetLocalSection(dm, &s);
2912: switch (mode) {
2913: case INSERT_VALUES:
2914: case INSERT_ALL_VALUES:
2915: isInsert = PETSC_TRUE; break;
2916: case ADD_VALUES:
2917: case ADD_ALL_VALUES:
2918: isInsert = PETSC_FALSE; break;
2919: default:
2920: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2921: }
2922: if (sf && !isInsert) {
2923: const PetscScalar *lArray;
2924: PetscScalar *gArray;
2925: Vec tmpl;
2927: DMHasBasisTransform(dm, &transform);
2928: if (transform) {
2929: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2930: VecGetArrayRead(tmpl, &lArray);
2931: } else {
2932: VecGetArrayReadAndMemType(l, &lArray, NULL);
2933: }
2934: VecGetArrayAndMemType(g, &gArray, NULL);
2935: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2936: if (transform) {
2937: VecRestoreArrayRead(tmpl, &lArray);
2938: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2939: } else {
2940: VecRestoreArrayReadAndMemType(l, &lArray);
2941: }
2942: VecRestoreArrayAndMemType(g, &gArray);
2943: } else if (s && isInsert) {
2944: } else {
2945: if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2946: (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2947: }
2948: for (link=dm->ltoghook; link; link=link->next) {
2949: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2950: }
2951: return(0);
2952: }
2954: /*@
2955: DMLocalToLocalBegin - Maps from a local vector (including ghost points
2956: that contain irrelevant values) to another local vector where the ghost
2957: points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2959: Neighbor-wise Collective on dm
2961: Input Parameters:
2962: + dm - the DM object
2963: . g - the original local vector
2964: - mode - one of INSERT_VALUES or ADD_VALUES
2966: Output Parameter:
2967: . l - the local vector with correct ghost values
2969: Level: intermediate
2971: Notes:
2972: The local vectors used here need not be the same as those
2973: obtained from DMCreateLocalVector(), BUT they
2974: must have the same parallel data layout; they could, for example, be
2975: obtained with VecDuplicate() from the DM originating vectors.
2977: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2979: @*/
2980: PetscErrorCode DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2981: {
2982: PetscErrorCode ierr;
2986: if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2987: (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2988: return(0);
2989: }
2991: /*@
2992: DMLocalToLocalEnd - Maps from a local vector (including ghost points
2993: that contain irrelevant values) to another local vector where the ghost
2994: points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2996: Neighbor-wise Collective on dm
2998: Input Parameters:
2999: + da - the DM object
3000: . g - the original local vector
3001: - mode - one of INSERT_VALUES or ADD_VALUES
3003: Output Parameter:
3004: . l - the local vector with correct ghost values
3006: Level: intermediate
3008: Notes:
3009: The local vectors used here need not be the same as those
3010: obtained from DMCreateLocalVector(), BUT they
3011: must have the same parallel data layout; they could, for example, be
3012: obtained with VecDuplicate() from the DM originating vectors.
3014: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3016: @*/
3017: PetscErrorCode DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3018: {
3019: PetscErrorCode ierr;
3023: if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
3024: (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3025: return(0);
3026: }
3029: /*@
3030: DMCoarsen - Coarsens a DM object
3032: Collective on dm
3034: Input Parameter:
3035: + dm - the DM object
3036: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
3038: Output Parameter:
3039: . dmc - the coarsened DM
3041: Level: developer
3043: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3045: @*/
3046: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3047: {
3048: PetscErrorCode ierr;
3049: DMCoarsenHookLink link;
3053: if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
3054: PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3055: (*dm->ops->coarsen)(dm, comm, dmc);
3056: if (*dmc) {
3057: DMSetCoarseDM(dm,*dmc);
3058: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3059: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3060: (*dmc)->ctx = dm->ctx;
3061: (*dmc)->levelup = dm->levelup;
3062: (*dmc)->leveldown = dm->leveldown + 1;
3063: DMSetMatType(*dmc,dm->mattype);
3064: for (link=dm->coarsenhook; link; link=link->next) {
3065: if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3066: }
3067: }
3068: PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3069: if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3070: return(0);
3071: }
3073: /*@C
3074: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3076: Logically Collective
3078: Input Arguments:
3079: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3080: . coarsenhook - function to run when setting up a coarser level
3081: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3082: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3084: Calling sequence of coarsenhook:
3085: $ coarsenhook(DM fine,DM coarse,void *ctx);
3087: + fine - fine level DM
3088: . coarse - coarse level DM to restrict problem to
3089: - ctx - optional user-defined function context
3091: Calling sequence for restricthook:
3092: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3094: + fine - fine level DM
3095: . mrestrict - matrix restricting a fine-level solution to the coarse grid
3096: . rscale - scaling vector for restriction
3097: . inject - matrix restricting by injection
3098: . coarse - coarse level DM to update
3099: - ctx - optional user-defined function context
3101: Level: advanced
3103: Notes:
3104: This function is only needed if auxiliary data needs to be set up on coarse grids.
3106: If this function is called multiple times, the hooks will be run in the order they are added.
3108: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3109: extract the finest level information from its context (instead of from the SNES).
3111: This function is currently not available from Fortran.
3113: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3114: @*/
3115: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3116: {
3117: PetscErrorCode ierr;
3118: DMCoarsenHookLink link,*p;
3122: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3123: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3124: }
3125: PetscNew(&link);
3126: link->coarsenhook = coarsenhook;
3127: link->restricthook = restricthook;
3128: link->ctx = ctx;
3129: link->next = NULL;
3130: *p = link;
3131: return(0);
3132: }
3134: /*@C
3135: DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
3137: Logically Collective
3139: Input Arguments:
3140: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3141: . coarsenhook - function to run when setting up a coarser level
3142: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3143: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3145: Level: advanced
3147: Notes:
3148: This function does nothing if the hook is not in the list.
3150: This function is currently not available from Fortran.
3152: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3153: @*/
3154: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3155: {
3156: PetscErrorCode ierr;
3157: DMCoarsenHookLink link,*p;
3161: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3162: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3163: link = *p;
3164: *p = link->next;
3165: PetscFree(link);
3166: break;
3167: }
3168: }
3169: return(0);
3170: }
3173: /*@
3174: DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
3176: Collective if any hooks are
3178: Input Arguments:
3179: + fine - finer DM to use as a base
3180: . restrct - restriction matrix, apply using MatRestrict()
3181: . rscale - scaling vector for restriction
3182: . inject - injection matrix, also use MatRestrict()
3183: - coarse - coarser DM to update
3185: Level: developer
3187: .seealso: DMCoarsenHookAdd(), MatRestrict()
3188: @*/
3189: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3190: {
3191: PetscErrorCode ierr;
3192: DMCoarsenHookLink link;
3195: for (link=fine->coarsenhook; link; link=link->next) {
3196: if (link->restricthook) {
3197: (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3198: }
3199: }
3200: return(0);
3201: }
3203: /*@C
3204: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3206: Logically Collective on global
3208: Input Arguments:
3209: + global - global DM
3210: . ddhook - function to run to pass data to the decomposition DM upon its creation
3211: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3212: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3215: Calling sequence for ddhook:
3216: $ ddhook(DM global,DM block,void *ctx)
3218: + global - global DM
3219: . block - block DM
3220: - ctx - optional user-defined function context
3222: Calling sequence for restricthook:
3223: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3225: + global - global DM
3226: . out - scatter to the outer (with ghost and overlap points) block vector
3227: . in - scatter to block vector values only owned locally
3228: . block - block DM
3229: - ctx - optional user-defined function context
3231: Level: advanced
3233: Notes:
3234: This function is only needed if auxiliary data needs to be set up on subdomain DMs.
3236: If this function is called multiple times, the hooks will be run in the order they are added.
3238: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3239: extract the global information from its context (instead of from the SNES).
3241: This function is currently not available from Fortran.
3243: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3244: @*/
3245: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3246: {
3247: PetscErrorCode ierr;
3248: DMSubDomainHookLink link,*p;
3252: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3253: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3254: }
3255: PetscNew(&link);
3256: link->restricthook = restricthook;
3257: link->ddhook = ddhook;
3258: link->ctx = ctx;
3259: link->next = NULL;
3260: *p = link;
3261: return(0);
3262: }
3264: /*@C
3265: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3267: Logically Collective
3269: Input Arguments:
3270: + global - global DM
3271: . ddhook - function to run to pass data to the decomposition DM upon its creation
3272: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3273: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3275: Level: advanced
3277: Notes:
3279: This function is currently not available from Fortran.
3281: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3282: @*/
3283: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3284: {
3285: PetscErrorCode ierr;
3286: DMSubDomainHookLink link,*p;
3290: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3291: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3292: link = *p;
3293: *p = link->next;
3294: PetscFree(link);
3295: break;
3296: }
3297: }
3298: return(0);
3299: }
3301: /*@
3302: DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
3304: Collective if any hooks are
3306: Input Arguments:
3307: + fine - finer DM to use as a base
3308: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3309: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3310: - coarse - coarer DM to update
3312: Level: developer
3314: .seealso: DMCoarsenHookAdd(), MatRestrict()
3315: @*/
3316: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3317: {
3318: PetscErrorCode ierr;
3319: DMSubDomainHookLink link;
3322: for (link=global->subdomainhook; link; link=link->next) {
3323: if (link->restricthook) {
3324: (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3325: }
3326: }
3327: return(0);
3328: }
3330: /*@
3331: DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
3333: Not Collective
3335: Input Parameter:
3336: . dm - the DM object
3338: Output Parameter:
3339: . level - number of coarsenings
3341: Level: developer
3343: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3345: @*/
3346: PetscErrorCode DMGetCoarsenLevel(DM dm,PetscInt *level)
3347: {
3351: *level = dm->leveldown;
3352: return(0);
3353: }
3355: /*@
3356: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
3358: Not Collective
3360: Input Parameters:
3361: + dm - the DM object
3362: - level - number of coarsenings
3364: Level: developer
3366: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3367: @*/
3368: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3369: {
3372: dm->leveldown = level;
3373: return(0);
3374: }
3378: /*@C
3379: DMRefineHierarchy - Refines a DM object, all levels at once
3381: Collective on dm
3383: Input Parameter:
3384: + dm - the DM object
3385: - nlevels - the number of levels of refinement
3387: Output Parameter:
3388: . dmf - the refined DM hierarchy
3390: Level: developer
3392: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3394: @*/
3395: PetscErrorCode DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3396: {
3401: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3402: if (nlevels == 0) return(0);
3404: if (dm->ops->refinehierarchy) {
3405: (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3406: } else if (dm->ops->refine) {
3407: PetscInt i;
3409: DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3410: for (i=1; i<nlevels; i++) {
3411: DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3412: }
3413: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3414: return(0);
3415: }
3417: /*@C
3418: DMCoarsenHierarchy - Coarsens a DM object, all levels at once
3420: Collective on dm
3422: Input Parameter:
3423: + dm - the DM object
3424: - nlevels - the number of levels of coarsening
3426: Output Parameter:
3427: . dmc - the coarsened DM hierarchy
3429: Level: developer
3431: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3433: @*/
3434: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3435: {
3440: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3441: if (nlevels == 0) return(0);
3443: if (dm->ops->coarsenhierarchy) {
3444: (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3445: } else if (dm->ops->coarsen) {
3446: PetscInt i;
3448: DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3449: for (i=1; i<nlevels; i++) {
3450: DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3451: }
3452: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3453: return(0);
3454: }
3456: /*@C
3457: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
3459: Not Collective
3461: Input Parameters:
3462: + dm - the DM object
3463: - destroy - the destroy function
3465: Level: intermediate
3467: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3469: @*/
3470: PetscErrorCode DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3471: {
3474: dm->ctxdestroy = destroy;
3475: return(0);
3476: }
3478: /*@
3479: DMSetApplicationContext - Set a user context into a DM object
3481: Not Collective
3483: Input Parameters:
3484: + dm - the DM object
3485: - ctx - the user context
3487: Level: intermediate
3489: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3491: @*/
3492: PetscErrorCode DMSetApplicationContext(DM dm,void *ctx)
3493: {
3496: dm->ctx = ctx;
3497: return(0);
3498: }
3500: /*@
3501: DMGetApplicationContext - Gets a user context from a DM object
3503: Not Collective
3505: Input Parameter:
3506: . dm - the DM object
3508: Output Parameter:
3509: . ctx - the user context
3511: Level: intermediate
3513: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3515: @*/
3516: PetscErrorCode DMGetApplicationContext(DM dm,void *ctx)
3517: {
3520: *(void**)ctx = dm->ctx;
3521: return(0);
3522: }
3524: /*@C
3525: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3527: Logically Collective on dm
3529: Input Parameter:
3530: + dm - the DM object
3531: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3533: Level: intermediate
3535: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3536: DMSetJacobian()
3538: @*/
3539: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3540: {
3543: dm->ops->computevariablebounds = f;
3544: return(0);
3545: }
3547: /*@
3548: DMHasVariableBounds - does the DM object have a variable bounds function?
3550: Not Collective
3552: Input Parameter:
3553: . dm - the DM object to destroy
3555: Output Parameter:
3556: . flg - PETSC_TRUE if the variable bounds function exists
3558: Level: developer
3560: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3562: @*/
3563: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3564: {
3568: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3569: return(0);
3570: }
3572: /*@C
3573: DMComputeVariableBounds - compute variable bounds used by SNESVI.
3575: Logically Collective on dm
3577: Input Parameters:
3578: . dm - the DM object
3580: Output parameters:
3581: + xl - lower bound
3582: - xu - upper bound
3584: Level: advanced
3586: Notes:
3587: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3589: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3591: @*/
3592: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3593: {
3600: if (!dm->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeVariableBounds",((PetscObject)dm)->type_name);
3601: (*dm->ops->computevariablebounds)(dm, xl,xu);
3602: return(0);
3603: }
3605: /*@
3606: DMHasColoring - does the DM object have a method of providing a coloring?
3608: Not Collective
3610: Input Parameter:
3611: . dm - the DM object
3613: Output Parameter:
3614: . flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3616: Level: developer
3618: .seealso DMCreateColoring()
3620: @*/
3621: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3622: {
3626: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3627: return(0);
3628: }
3630: /*@
3631: DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3633: Not Collective
3635: Input Parameter:
3636: . dm - the DM object
3638: Output Parameter:
3639: . flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3641: Level: developer
3643: .seealso DMCreateRestriction()
3645: @*/
3646: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3647: {
3651: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3652: return(0);
3653: }
3656: /*@
3657: DMHasCreateInjection - does the DM object have a method of providing an injection?
3659: Not Collective
3661: Input Parameter:
3662: . dm - the DM object
3664: Output Parameter:
3665: . flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3667: Level: developer
3669: .seealso DMCreateInjection()
3671: @*/
3672: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3673: {
3679: if (dm->ops->hascreateinjection) {
3680: (*dm->ops->hascreateinjection)(dm,flg);
3681: } else {
3682: *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3683: }
3684: return(0);
3685: }
3687: PetscFunctionList DMList = NULL;
3688: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3690: /*@C
3691: DMSetType - Builds a DM, for a particular DM implementation.
3693: Collective on dm
3695: Input Parameters:
3696: + dm - The DM object
3697: - method - The name of the DM type
3699: Options Database Key:
3700: . -dm_type <type> - Sets the DM type; use -help for a list of available types
3702: Notes:
3703: See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3705: Level: intermediate
3707: .seealso: DMGetType(), DMCreate()
3708: @*/
3709: PetscErrorCode DMSetType(DM dm, DMType method)
3710: {
3711: PetscErrorCode (*r)(DM);
3712: PetscBool match;
3717: PetscObjectTypeCompare((PetscObject) dm, method, &match);
3718: if (match) return(0);
3720: DMRegisterAll();
3721: PetscFunctionListFind(DMList,method,&r);
3722: if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3724: if (dm->ops->destroy) {
3725: (*dm->ops->destroy)(dm);
3726: }
3727: PetscMemzero(dm->ops,sizeof(*dm->ops));
3728: PetscObjectChangeTypeName((PetscObject)dm,method);
3729: (*r)(dm);
3730: return(0);
3731: }
3733: /*@C
3734: DMGetType - Gets the DM type name (as a string) from the DM.
3736: Not Collective
3738: Input Parameter:
3739: . dm - The DM
3741: Output Parameter:
3742: . type - The DM type name
3744: Level: intermediate
3746: .seealso: DMSetType(), DMCreate()
3747: @*/
3748: PetscErrorCode DMGetType(DM dm, DMType *type)
3749: {
3755: DMRegisterAll();
3756: *type = ((PetscObject)dm)->type_name;
3757: return(0);
3758: }
3760: /*@C
3761: DMConvert - Converts a DM to another DM, either of the same or different type.
3763: Collective on dm
3765: Input Parameters:
3766: + dm - the DM
3767: - newtype - new DM type (use "same" for the same type)
3769: Output Parameter:
3770: . M - pointer to new DM
3772: Notes:
3773: Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3774: the MPI communicator of the generated DM is always the same as the communicator
3775: of the input DM.
3777: Level: intermediate
3779: .seealso: DMCreate()
3780: @*/
3781: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3782: {
3783: DM B;
3784: char convname[256];
3785: PetscBool sametype/*, issame */;
3792: PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3793: /* PetscStrcmp(newtype, "same", &issame); */
3794: if (sametype) {
3795: *M = dm;
3796: PetscObjectReference((PetscObject) dm);
3797: return(0);
3798: } else {
3799: PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3801: /*
3802: Order of precedence:
3803: 1) See if a specialized converter is known to the current DM.
3804: 2) See if a specialized converter is known to the desired DM class.
3805: 3) See if a good general converter is registered for the desired class
3806: 4) See if a good general converter is known for the current matrix.
3807: 5) Use a really basic converter.
3808: */
3810: /* 1) See if a specialized converter is known to the current DM and the desired class */
3811: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3812: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3813: PetscStrlcat(convname,"_",sizeof(convname));
3814: PetscStrlcat(convname,newtype,sizeof(convname));
3815: PetscStrlcat(convname,"_C",sizeof(convname));
3816: PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3817: if (conv) goto foundconv;
3819: /* 2) See if a specialized converter is known to the desired DM class. */
3820: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3821: DMSetType(B, newtype);
3822: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3823: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3824: PetscStrlcat(convname,"_",sizeof(convname));
3825: PetscStrlcat(convname,newtype,sizeof(convname));
3826: PetscStrlcat(convname,"_C",sizeof(convname));
3827: PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3828: if (conv) {
3829: DMDestroy(&B);
3830: goto foundconv;
3831: }
3833: #if 0
3834: /* 3) See if a good general converter is registered for the desired class */
3835: conv = B->ops->convertfrom;
3836: DMDestroy(&B);
3837: if (conv) goto foundconv;
3839: /* 4) See if a good general converter is known for the current matrix */
3840: if (dm->ops->convert) {
3841: conv = dm->ops->convert;
3842: }
3843: if (conv) goto foundconv;
3844: #endif
3846: /* 5) Use a really basic converter. */
3847: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3849: foundconv:
3850: PetscLogEventBegin(DM_Convert,dm,0,0,0);
3851: (*conv)(dm,newtype,M);
3852: /* Things that are independent of DM type: We should consult DMClone() here */
3853: {
3854: PetscBool isper;
3855: const PetscReal *maxCell, *L;
3856: const DMBoundaryType *bd;
3857: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3858: DMSetPeriodicity(*M, isper, maxCell, L, bd);
3859: (*M)->prealloc_only = dm->prealloc_only;
3860: PetscFree((*M)->vectype);
3861: PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3862: PetscFree((*M)->mattype);
3863: PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3864: }
3865: PetscLogEventEnd(DM_Convert,dm,0,0,0);
3866: }
3867: PetscObjectStateIncrease((PetscObject) *M);
3868: return(0);
3869: }
3871: /*--------------------------------------------------------------------------------------------------------------------*/
3873: /*@C
3874: DMRegister - Adds a new DM component implementation
3876: Not Collective
3878: Input Parameters:
3879: + name - The name of a new user-defined creation routine
3880: - create_func - The creation routine itself
3882: Notes:
3883: DMRegister() may be called multiple times to add several user-defined DMs
3886: Sample usage:
3887: .vb
3888: DMRegister("my_da", MyDMCreate);
3889: .ve
3891: Then, your DM type can be chosen with the procedural interface via
3892: .vb
3893: DMCreate(MPI_Comm, DM *);
3894: DMSetType(DM,"my_da");
3895: .ve
3896: or at runtime via the option
3897: .vb
3898: -da_type my_da
3899: .ve
3901: Level: advanced
3903: .seealso: DMRegisterAll(), DMRegisterDestroy()
3905: @*/
3906: PetscErrorCode DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3907: {
3911: DMInitializePackage();
3912: PetscFunctionListAdd(&DMList,sname,function);
3913: return(0);
3914: }
3916: /*@C
3917: DMLoad - Loads a DM that has been stored in binary with DMView().
3919: Collective on viewer
3921: Input Parameters:
3922: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3923: some related function before a call to DMLoad().
3924: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3925: HDF5 file viewer, obtained from PetscViewerHDF5Open()
3927: Level: intermediate
3929: Notes:
3930: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3932: Notes for advanced users:
3933: Most users should not need to know the details of the binary storage
3934: format, since DMLoad() and DMView() completely hide these details.
3935: But for anyone who's interested, the standard binary matrix storage
3936: format is
3937: .vb
3938: has not yet been determined
3939: .ve
3941: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3942: @*/
3943: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
3944: {
3945: PetscBool isbinary, ishdf5;
3951: PetscViewerCheckReadable(viewer);
3952: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3953: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3954: PetscLogEventBegin(DM_Load,viewer,0,0,0);
3955: if (isbinary) {
3956: PetscInt classid;
3957: char type[256];
3959: PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3960: if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3961: PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3962: DMSetType(newdm, type);
3963: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3964: } else if (ishdf5) {
3965: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3966: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3967: PetscLogEventEnd(DM_Load,viewer,0,0,0);
3968: return(0);
3969: }
3971: /*@
3972: DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
3974: Not collective
3976: Input Parameter:
3977: . dm - the DM
3979: Output Parameters:
3980: + lmin - local minimum coordinates (length coord dim, optional)
3981: - lmax - local maximim coordinates (length coord dim, optional)
3983: Level: beginner
3985: Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
3988: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3989: @*/
3990: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3991: {
3992: Vec coords = NULL;
3993: PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3994: PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3995: const PetscScalar *local_coords;
3996: PetscInt N, Ni;
3997: PetscInt cdim, i, j;
3998: PetscErrorCode ierr;
4002: DMGetCoordinateDim(dm, &cdim);
4003: DMGetCoordinates(dm, &coords);
4004: if (coords) {
4005: VecGetArrayRead(coords, &local_coords);
4006: VecGetLocalSize(coords, &N);
4007: Ni = N/cdim;
4008: for (i = 0; i < Ni; ++i) {
4009: for (j = 0; j < 3; ++j) {
4010: min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4011: max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4012: }
4013: }
4014: VecRestoreArrayRead(coords, &local_coords);
4015: } else {
4016: PetscBool isda;
4018: PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4019: if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4020: }
4021: if (lmin) {PetscArraycpy(lmin, min, cdim);}
4022: if (lmax) {PetscArraycpy(lmax, max, cdim);}
4023: return(0);
4024: }
4026: /*@
4027: DMGetBoundingBox - Returns the global bounding box for the DM.
4029: Collective
4031: Input Parameter:
4032: . dm - the DM
4034: Output Parameters:
4035: + gmin - global minimum coordinates (length coord dim, optional)
4036: - gmax - global maximim coordinates (length coord dim, optional)
4038: Level: beginner
4040: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4041: @*/
4042: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4043: {
4044: PetscReal lmin[3], lmax[3];
4045: PetscInt cdim;
4046: PetscMPIInt count;
4051: DMGetCoordinateDim(dm, &cdim);
4052: PetscMPIIntCast(cdim, &count);
4053: DMGetLocalBoundingBox(dm, lmin, lmax);
4054: if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4055: if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4056: return(0);
4057: }
4059: /******************************** FEM Support **********************************/
4061: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4062: {
4063: PetscInt f;
4067: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4068: for (f = 0; f < len; ++f) {
4069: PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
4070: }
4071: return(0);
4072: }
4074: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4075: {
4076: PetscInt f, g;
4080: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4081: for (f = 0; f < rows; ++f) {
4082: PetscPrintf(PETSC_COMM_SELF, " |");
4083: for (g = 0; g < cols; ++g) {
4084: PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4085: }
4086: PetscPrintf(PETSC_COMM_SELF, " |\n");
4087: }
4088: return(0);
4089: }
4091: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4092: {
4093: PetscInt localSize, bs;
4094: PetscMPIInt size;
4095: Vec x, xglob;
4096: const PetscScalar *xarray;
4097: PetscErrorCode ierr;
4100: MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4101: VecDuplicate(X, &x);
4102: VecCopy(X, x);
4103: VecChop(x, tol);
4104: PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4105: if (size > 1) {
4106: VecGetLocalSize(x,&localSize);
4107: VecGetArrayRead(x,&xarray);
4108: VecGetBlockSize(x,&bs);
4109: VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4110: } else {
4111: xglob = x;
4112: }
4113: VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4114: if (size > 1) {
4115: VecDestroy(&xglob);
4116: VecRestoreArrayRead(x,&xarray);
4117: }
4118: VecDestroy(&x);
4119: return(0);
4120: }
4122: /*@
4123: DMGetSection - Get the PetscSection encoding the local data layout for the DM. This is equivalent to DMGetLocalSection(). Deprecated in v3.12
4125: Input Parameter:
4126: . dm - The DM
4128: Output Parameter:
4129: . section - The PetscSection
4131: Options Database Keys:
4132: . -dm_petscsection_view - View the Section created by the DM
4134: Level: advanced
4136: Notes:
4137: Use DMGetLocalSection() in new code.
4139: This gets a borrowed reference, so the user should not destroy this PetscSection.
4141: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4142: @*/
4143: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4144: {
4148: DMGetLocalSection(dm,section);
4149: return(0);
4150: }
4152: /*@
4153: DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
4155: Input Parameter:
4156: . dm - The DM
4158: Output Parameter:
4159: . section - The PetscSection
4161: Options Database Keys:
4162: . -dm_petscsection_view - View the Section created by the DM
4164: Level: intermediate
4166: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4168: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4169: @*/
4170: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4171: {
4177: if (!dm->localSection && dm->ops->createlocalsection) {
4178: PetscInt d;
4180: if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4181: (*dm->ops->createlocalsection)(dm);
4182: if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4183: }
4184: *section = dm->localSection;
4185: return(0);
4186: }
4188: /*@
4189: DMSetSection - Set the PetscSection encoding the local data layout for the DM. This is equivalent to DMSetLocalSection(). Deprecated in v3.12
4191: Input Parameters:
4192: + dm - The DM
4193: - section - The PetscSection
4195: Level: advanced
4197: Notes:
4198: Use DMSetLocalSection() in new code.
4200: Any existing Section will be destroyed
4202: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4203: @*/
4204: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4205: {
4209: DMSetLocalSection(dm,section);
4210: return(0);
4211: }
4213: /*@
4214: DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
4216: Input Parameters:
4217: + dm - The DM
4218: - section - The PetscSection
4220: Level: intermediate
4222: Note: Any existing Section will be destroyed
4224: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4225: @*/
4226: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4227: {
4228: PetscInt numFields = 0;
4229: PetscInt f;
4235: PetscObjectReference((PetscObject)section);
4236: PetscSectionDestroy(&dm->localSection);
4237: dm->localSection = section;
4238: if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4239: if (numFields) {
4240: DMSetNumFields(dm, numFields);
4241: for (f = 0; f < numFields; ++f) {
4242: PetscObject disc;
4243: const char *name;
4245: PetscSectionGetFieldName(dm->localSection, f, &name);
4246: DMGetField(dm, f, NULL, &disc);
4247: PetscObjectSetName(disc, name);
4248: }
4249: }
4250: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4251: PetscSectionDestroy(&dm->globalSection);
4252: return(0);
4253: }
4255: /*@
4256: DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4258: not collective
4260: Input Parameter:
4261: . dm - The DM
4263: Output Parameter:
4264: + 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.
4265: - 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.
4267: Level: advanced
4269: Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
4271: .seealso: DMSetDefaultConstraints()
4272: @*/
4273: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4274: {
4279: if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4280: if (section) {*section = dm->defaultConstraintSection;}
4281: if (mat) {*mat = dm->defaultConstraintMat;}
4282: return(0);
4283: }
4285: /*@
4286: DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4288: 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().
4290: 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.
4292: collective on dm
4294: Input Parameters:
4295: + dm - The DM
4296: + 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).
4297: - 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).
4299: Level: advanced
4301: Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
4303: .seealso: DMGetDefaultConstraints()
4304: @*/
4305: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4306: {
4307: PetscMPIInt result;
4312: if (section) {
4314: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4315: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4316: }
4317: if (mat) {
4319: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4320: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4321: }
4322: PetscObjectReference((PetscObject)section);
4323: PetscSectionDestroy(&dm->defaultConstraintSection);
4324: dm->defaultConstraintSection = section;
4325: PetscObjectReference((PetscObject)mat);
4326: MatDestroy(&dm->defaultConstraintMat);
4327: dm->defaultConstraintMat = mat;
4328: return(0);
4329: }
4331: #if defined(PETSC_USE_DEBUG)
4332: /*
4333: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4335: Input Parameters:
4336: + dm - The DM
4337: . localSection - PetscSection describing the local data layout
4338: - globalSection - PetscSection describing the global data layout
4340: Level: intermediate
4342: .seealso: DMGetSectionSF(), DMSetSectionSF()
4343: */
4344: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4345: {
4346: MPI_Comm comm;
4347: PetscLayout layout;
4348: const PetscInt *ranges;
4349: PetscInt pStart, pEnd, p, nroots;
4350: PetscMPIInt size, rank;
4351: PetscBool valid = PETSC_TRUE, gvalid;
4352: PetscErrorCode ierr;
4355: PetscObjectGetComm((PetscObject)dm,&comm);
4357: MPI_Comm_size(comm, &size);
4358: MPI_Comm_rank(comm, &rank);
4359: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4360: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4361: PetscLayoutCreate(comm, &layout);
4362: PetscLayoutSetBlockSize(layout, 1);
4363: PetscLayoutSetLocalSize(layout, nroots);
4364: PetscLayoutSetUp(layout);
4365: PetscLayoutGetRanges(layout, &ranges);
4366: for (p = pStart; p < pEnd; ++p) {
4367: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4369: PetscSectionGetDof(localSection, p, &dof);
4370: PetscSectionGetOffset(localSection, p, &off);
4371: PetscSectionGetConstraintDof(localSection, p, &cdof);
4372: PetscSectionGetDof(globalSection, p, &gdof);
4373: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4374: PetscSectionGetOffset(globalSection, p, &goff);
4375: if (!gdof) continue; /* Censored point */
4376: 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;}
4377: 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;}
4378: if (gdof < 0) {
4379: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4380: for (d = 0; d < gsize; ++d) {
4381: PetscInt offset = -(goff+1) + d, r;
4383: PetscFindInt(offset,size+1,ranges,&r);
4384: if (r < 0) r = -(r+2);
4385: 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;}
4386: }
4387: }
4388: }
4389: PetscLayoutDestroy(&layout);
4390: PetscSynchronizedFlush(comm, NULL);
4391: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4392: if (!gvalid) {
4393: DMView(dm, NULL);
4394: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4395: }
4396: return(0);
4397: }
4398: #endif
4400: /*@
4401: DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4403: Collective on dm
4405: Input Parameter:
4406: . dm - The DM
4408: Output Parameter:
4409: . section - The PetscSection
4411: Level: intermediate
4413: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4415: .seealso: DMSetLocalSection(), DMGetLocalSection()
4416: @*/
4417: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4418: {
4424: if (!dm->globalSection) {
4425: PetscSection s;
4427: DMGetLocalSection(dm, &s);
4428: if (!s) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4429: if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4430: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4431: PetscLayoutDestroy(&dm->map);
4432: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4433: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4434: }
4435: *section = dm->globalSection;
4436: return(0);
4437: }
4439: /*@
4440: DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4442: Input Parameters:
4443: + dm - The DM
4444: - section - The PetscSection, or NULL
4446: Level: intermediate
4448: Note: Any existing Section will be destroyed
4450: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4451: @*/
4452: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4453: {
4459: PetscObjectReference((PetscObject)section);
4460: PetscSectionDestroy(&dm->globalSection);
4461: dm->globalSection = section;
4462: #if defined(PETSC_USE_DEBUG)
4463: if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4464: #endif
4465: return(0);
4466: }
4468: /*@
4469: DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4470: it is created from the default PetscSection layouts in the DM.
4472: Input Parameter:
4473: . dm - The DM
4475: Output Parameter:
4476: . sf - The PetscSF
4478: Level: intermediate
4480: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4482: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4483: @*/
4484: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4485: {
4486: PetscInt nroots;
4492: if (!dm->sectionSF) {
4493: PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4494: }
4495: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4496: if (nroots < 0) {
4497: PetscSection section, gSection;
4499: DMGetLocalSection(dm, §ion);
4500: if (section) {
4501: DMGetGlobalSection(dm, &gSection);
4502: DMCreateSectionSF(dm, section, gSection);
4503: } else {
4504: *sf = NULL;
4505: return(0);
4506: }
4507: }
4508: *sf = dm->sectionSF;
4509: return(0);
4510: }
4512: /*@
4513: DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4515: Input Parameters:
4516: + dm - The DM
4517: - sf - The PetscSF
4519: Level: intermediate
4521: Note: Any previous SF is destroyed
4523: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4524: @*/
4525: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4526: {
4532: PetscObjectReference((PetscObject) sf);
4533: PetscSFDestroy(&dm->sectionSF);
4534: dm->sectionSF = sf;
4535: return(0);
4536: }
4538: /*@C
4539: DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4540: describing the data layout.
4542: Input Parameters:
4543: + dm - The DM
4544: . localSection - PetscSection describing the local data layout
4545: - globalSection - PetscSection describing the global data layout
4547: Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4549: Level: developer
4551: Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4552: directly into the DM, perhaps this function should not take the local and global sections as
4553: input and should just obtain them from the DM?
4555: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4556: @*/
4557: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4558: {
4563: PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4564: return(0);
4565: }
4567: /*@
4568: DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4570: Input Parameter:
4571: . dm - The DM
4573: Output Parameter:
4574: . sf - The PetscSF
4576: Level: intermediate
4578: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4580: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4581: @*/
4582: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4583: {
4587: *sf = dm->sf;
4588: return(0);
4589: }
4591: /*@
4592: DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4594: Input Parameters:
4595: + dm - The DM
4596: - sf - The PetscSF
4598: Level: intermediate
4600: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4601: @*/
4602: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4603: {
4609: PetscObjectReference((PetscObject) sf);
4610: PetscSFDestroy(&dm->sf);
4611: dm->sf = sf;
4612: return(0);
4613: }
4615: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4616: {
4617: PetscClassId id;
4621: PetscObjectGetClassId(disc, &id);
4622: if (id == PETSCFE_CLASSID) {
4623: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4624: } else if (id == PETSCFV_CLASSID) {
4625: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4626: } else {
4627: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4628: }
4629: return(0);
4630: }
4632: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4633: {
4634: RegionField *tmpr;
4635: PetscInt Nf = dm->Nf, f;
4639: if (Nf >= NfNew) return(0);
4640: PetscMalloc1(NfNew, &tmpr);
4641: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4642: for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4643: PetscFree(dm->fields);
4644: dm->Nf = NfNew;
4645: dm->fields = tmpr;
4646: return(0);
4647: }
4649: /*@
4650: DMClearFields - Remove all fields from the DM
4652: Logically collective on dm
4654: Input Parameter:
4655: . dm - The DM
4657: Level: intermediate
4659: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4660: @*/
4661: PetscErrorCode DMClearFields(DM dm)
4662: {
4663: PetscInt f;
4668: for (f = 0; f < dm->Nf; ++f) {
4669: PetscObjectDestroy(&dm->fields[f].disc);
4670: DMLabelDestroy(&dm->fields[f].label);
4671: }
4672: PetscFree(dm->fields);
4673: dm->fields = NULL;
4674: dm->Nf = 0;
4675: return(0);
4676: }
4678: /*@
4679: DMGetNumFields - Get the number of fields in the DM
4681: Not collective
4683: Input Parameter:
4684: . dm - The DM
4686: Output Parameter:
4687: . Nf - The number of fields
4689: Level: intermediate
4691: .seealso: DMSetNumFields(), DMSetField()
4692: @*/
4693: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4694: {
4698: *numFields = dm->Nf;
4699: return(0);
4700: }
4702: /*@
4703: DMSetNumFields - Set the number of fields in the DM
4705: Logically collective on dm
4707: Input Parameters:
4708: + dm - The DM
4709: - Nf - The number of fields
4711: Level: intermediate
4713: .seealso: DMGetNumFields(), DMSetField()
4714: @*/
4715: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4716: {
4717: PetscInt Nf, f;
4722: DMGetNumFields(dm, &Nf);
4723: for (f = Nf; f < numFields; ++f) {
4724: PetscContainer obj;
4726: PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4727: DMAddField(dm, NULL, (PetscObject) obj);
4728: PetscContainerDestroy(&obj);
4729: }
4730: return(0);
4731: }
4733: /*@
4734: DMGetField - Return the discretization object for a given DM field
4736: Not collective
4738: Input Parameters:
4739: + dm - The DM
4740: - f - The field number
4742: Output Parameters:
4743: + label - The label indicating the support of the field, or NULL for the entire mesh
4744: - field - The discretization object
4746: Level: intermediate
4748: .seealso: DMAddField(), DMSetField()
4749: @*/
4750: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4751: {
4755: 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);
4756: if (label) *label = dm->fields[f].label;
4757: if (field) *field = dm->fields[f].disc;
4758: return(0);
4759: }
4761: /* Does not clear the DS */
4762: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4763: {
4767: DMFieldEnlarge_Static(dm, f+1);
4768: DMLabelDestroy(&dm->fields[f].label);
4769: PetscObjectDestroy(&dm->fields[f].disc);
4770: dm->fields[f].label = label;
4771: dm->fields[f].disc = field;
4772: PetscObjectReference((PetscObject) label);
4773: PetscObjectReference((PetscObject) field);
4774: return(0);
4775: }
4777: /*@
4778: DMSetField - Set the discretization object for a given DM field
4780: Logically collective on dm
4782: Input Parameters:
4783: + dm - The DM
4784: . f - The field number
4785: . label - The label indicating the support of the field, or NULL for the entire mesh
4786: - field - The discretization object
4788: Level: intermediate
4790: .seealso: DMAddField(), DMGetField()
4791: @*/
4792: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4793: {
4800: if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4801: DMSetField_Internal(dm, f, label, field);
4802: DMSetDefaultAdjacency_Private(dm, f, field);
4803: DMClearDS(dm);
4804: return(0);
4805: }
4807: /*@
4808: DMAddField - Add the discretization object for the given DM field
4810: Logically collective on dm
4812: Input Parameters:
4813: + dm - The DM
4814: . label - The label indicating the support of the field, or NULL for the entire mesh
4815: - field - The discretization object
4817: Level: intermediate
4819: .seealso: DMSetField(), DMGetField()
4820: @*/
4821: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4822: {
4823: PetscInt Nf = dm->Nf;
4830: DMFieldEnlarge_Static(dm, Nf+1);
4831: dm->fields[Nf].label = label;
4832: dm->fields[Nf].disc = field;
4833: PetscObjectReference((PetscObject) label);
4834: PetscObjectReference((PetscObject) field);
4835: DMSetDefaultAdjacency_Private(dm, Nf, field);
4836: DMClearDS(dm);
4837: return(0);
4838: }
4840: /*@
4841: DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4843: Logically collective on dm
4845: Input Parameters:
4846: + dm - The DM
4847: . f - The field index
4848: - avoidTensor - The flag to avoid defining the field on tensor cells
4850: Level: intermediate
4852: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4853: @*/
4854: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4855: {
4857: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4858: dm->fields[f].avoidTensor = avoidTensor;
4859: return(0);
4860: }
4862: /*@
4863: DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4865: Logically collective on dm
4867: Input Parameters:
4868: + dm - The DM
4869: - f - The field index
4871: Output Parameter:
4872: . avoidTensor - The flag to avoid defining the field on tensor cells
4874: Level: intermediate
4876: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4877: @*/
4878: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4879: {
4881: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4882: *avoidTensor = dm->fields[f].avoidTensor;
4883: return(0);
4884: }
4886: /*@
4887: DMCopyFields - Copy the discretizations for the DM into another DM
4889: Collective on dm
4891: Input Parameter:
4892: . dm - The DM
4894: Output Parameter:
4895: . newdm - The DM
4897: Level: advanced
4899: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4900: @*/
4901: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4902: {
4903: PetscInt Nf, f;
4907: if (dm == newdm) return(0);
4908: DMGetNumFields(dm, &Nf);
4909: DMClearFields(newdm);
4910: for (f = 0; f < Nf; ++f) {
4911: DMLabel label;
4912: PetscObject field;
4913: PetscBool useCone, useClosure;
4915: DMGetField(dm, f, &label, &field);
4916: DMSetField(newdm, f, label, field);
4917: DMGetAdjacency(dm, f, &useCone, &useClosure);
4918: DMSetAdjacency(newdm, f, useCone, useClosure);
4919: }
4920: return(0);
4921: }
4923: /*@
4924: DMGetAdjacency - Returns the flags for determining variable influence
4926: Not collective
4928: Input Parameters:
4929: + dm - The DM object
4930: - f - The field number, or PETSC_DEFAULT for the default adjacency
4932: Output Parameter:
4933: + useCone - Flag for variable influence starting with the cone operation
4934: - useClosure - Flag for variable influence using transitive closure
4936: Notes:
4937: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4938: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4939: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4940: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4942: Level: developer
4944: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4945: @*/
4946: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4947: {
4952: if (f < 0) {
4953: if (useCone) *useCone = dm->adjacency[0];
4954: if (useClosure) *useClosure = dm->adjacency[1];
4955: } else {
4956: PetscInt Nf;
4959: DMGetNumFields(dm, &Nf);
4960: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4961: if (useCone) *useCone = dm->fields[f].adjacency[0];
4962: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4963: }
4964: return(0);
4965: }
4967: /*@
4968: DMSetAdjacency - Set the flags for determining variable influence
4970: Not collective
4972: Input Parameters:
4973: + dm - The DM object
4974: . f - The field number
4975: . useCone - Flag for variable influence starting with the cone operation
4976: - useClosure - Flag for variable influence using transitive closure
4978: Notes:
4979: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4980: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4981: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4982: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4984: Level: developer
4986: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4987: @*/
4988: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4989: {
4992: if (f < 0) {
4993: dm->adjacency[0] = useCone;
4994: dm->adjacency[1] = useClosure;
4995: } else {
4996: PetscInt Nf;
4999: DMGetNumFields(dm, &Nf);
5000: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5001: dm->fields[f].adjacency[0] = useCone;
5002: dm->fields[f].adjacency[1] = useClosure;
5003: }
5004: return(0);
5005: }
5007: /*@
5008: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5010: Not collective
5012: Input Parameters:
5013: . dm - The DM object
5015: Output Parameter:
5016: + useCone - Flag for variable influence starting with the cone operation
5017: - useClosure - Flag for variable influence using transitive closure
5019: Notes:
5020: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5021: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5022: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5024: Level: developer
5026: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5027: @*/
5028: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5029: {
5030: PetscInt Nf;
5037: DMGetNumFields(dm, &Nf);
5038: if (!Nf) {
5039: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5040: } else {
5041: DMGetAdjacency(dm, 0, useCone, useClosure);
5042: }
5043: return(0);
5044: }
5046: /*@
5047: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5049: Not collective
5051: Input Parameters:
5052: + dm - The DM object
5053: . useCone - Flag for variable influence starting with the cone operation
5054: - useClosure - Flag for variable influence using transitive closure
5056: Notes:
5057: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5058: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5059: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5061: Level: developer
5063: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5064: @*/
5065: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5066: {
5067: PetscInt Nf;
5072: DMGetNumFields(dm, &Nf);
5073: if (!Nf) {
5074: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5075: } else {
5076: DMSetAdjacency(dm, 0, useCone, useClosure);
5077: }
5078: return(0);
5079: }
5081: /* Complete labels that are being used for FEM BC */
5082: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5083: {
5084: DMLabel label;
5085: PetscObject obj;
5086: PetscClassId id;
5087: PetscInt Nbd, bd;
5088: PetscBool isFE = PETSC_FALSE;
5089: PetscBool duplicate = PETSC_FALSE;
5093: DMGetField(dm, field, NULL, &obj);
5094: PetscObjectGetClassId(obj, &id);
5095: if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5096: DMGetLabel(dm, labelname, &label);
5097: if (isFE && label) {
5098: /* Only want to modify label once */
5099: PetscDSGetNumBoundary(ds, &Nbd);
5100: for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5101: const char *lname;
5103: PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5104: PetscStrcmp(lname, labelname, &duplicate);
5105: if (duplicate) break;
5106: }
5107: if (!duplicate) {
5108: DM plex;
5110: DMConvert(dm, DMPLEX, &plex);
5111: if (plex) {DMPlexLabelComplete(plex, label);}
5112: DMDestroy(&plex);
5113: }
5114: }
5115: return(0);
5116: }
5118: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5119: {
5120: DMSpace *tmpd;
5121: PetscInt Nds = dm->Nds, s;
5125: if (Nds >= NdsNew) return(0);
5126: PetscMalloc1(NdsNew, &tmpd);
5127: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5128: for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5129: PetscFree(dm->probs);
5130: dm->Nds = NdsNew;
5131: dm->probs = tmpd;
5132: return(0);
5133: }
5135: /*@
5136: DMGetNumDS - Get the number of discrete systems in the DM
5138: Not collective
5140: Input Parameter:
5141: . dm - The DM
5143: Output Parameter:
5144: . Nds - The number of PetscDS objects
5146: Level: intermediate
5148: .seealso: DMGetDS(), DMGetCellDS()
5149: @*/
5150: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5151: {
5155: *Nds = dm->Nds;
5156: return(0);
5157: }
5159: /*@
5160: DMClearDS - Remove all discrete systems from the DM
5162: Logically collective on dm
5164: Input Parameter:
5165: . dm - The DM
5167: Level: intermediate
5169: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5170: @*/
5171: PetscErrorCode DMClearDS(DM dm)
5172: {
5173: PetscInt s;
5178: for (s = 0; s < dm->Nds; ++s) {
5179: PetscDSDestroy(&dm->probs[s].ds);
5180: DMLabelDestroy(&dm->probs[s].label);
5181: ISDestroy(&dm->probs[s].fields);
5182: }
5183: PetscFree(dm->probs);
5184: dm->probs = NULL;
5185: dm->Nds = 0;
5186: return(0);
5187: }
5189: /*@
5190: DMGetDS - Get the default PetscDS
5192: Not collective
5194: Input Parameter:
5195: . dm - The DM
5197: Output Parameter:
5198: . prob - The default PetscDS
5200: Level: intermediate
5202: .seealso: DMGetCellDS(), DMGetRegionDS()
5203: @*/
5204: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5205: {
5211: if (dm->Nds <= 0) {
5212: PetscDS ds;
5214: PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5215: DMSetRegionDS(dm, NULL, NULL, ds);
5216: PetscDSDestroy(&ds);
5217: }
5218: *prob = dm->probs[0].ds;
5219: return(0);
5220: }
5222: /*@
5223: DMGetCellDS - Get the PetscDS defined on a given cell
5225: Not collective
5227: Input Parameters:
5228: + dm - The DM
5229: - point - Cell for the DS
5231: Output Parameter:
5232: . prob - The PetscDS defined on the given cell
5234: Level: developer
5236: .seealso: DMGetDS(), DMSetRegionDS()
5237: @*/
5238: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5239: {
5240: PetscDS probDef = NULL;
5241: PetscInt s;
5247: if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5248: *prob = NULL;
5249: for (s = 0; s < dm->Nds; ++s) {
5250: PetscInt val;
5252: if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5253: else {
5254: DMLabelGetValue(dm->probs[s].label, point, &val);
5255: if (val >= 0) {*prob = dm->probs[s].ds; break;}
5256: }
5257: }
5258: if (!*prob) *prob = probDef;
5259: return(0);
5260: }
5262: /*@
5263: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5265: Not collective
5267: Input Parameters:
5268: + dm - The DM
5269: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5271: Output Parameters:
5272: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5273: - prob - The PetscDS defined on the given region, or NULL
5275: Note: If the label is missing, this function returns an error
5277: Level: advanced
5279: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5280: @*/
5281: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5282: {
5283: PetscInt Nds = dm->Nds, s;
5290: for (s = 0; s < Nds; ++s) {
5291: if (dm->probs[s].label == label) {
5292: if (fields) *fields = dm->probs[s].fields;
5293: if (ds) *ds = dm->probs[s].ds;
5294: return(0);
5295: }
5296: }
5297: return(0);
5298: }
5300: /*@
5301: DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5303: Collective on dm
5305: Input Parameters:
5306: + dm - The DM
5307: . label - The DMLabel defining the mesh region, or NULL for the entire mesh
5308: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5309: - prob - The PetscDS defined on the given cell
5311: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5312: the fields argument is ignored.
5314: Level: advanced
5316: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5317: @*/
5318: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5319: {
5320: PetscInt Nds = dm->Nds, s;
5327: for (s = 0; s < Nds; ++s) {
5328: if (dm->probs[s].label == label) {
5329: PetscDSDestroy(&dm->probs[s].ds);
5330: dm->probs[s].ds = ds;
5331: return(0);
5332: }
5333: }
5334: DMDSEnlarge_Static(dm, Nds+1);
5335: PetscObjectReference((PetscObject) label);
5336: PetscObjectReference((PetscObject) fields);
5337: PetscObjectReference((PetscObject) ds);
5338: if (!label) {
5339: /* Put the NULL label at the front, so it is returned as the default */
5340: for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5341: Nds = 0;
5342: }
5343: dm->probs[Nds].label = label;
5344: dm->probs[Nds].fields = fields;
5345: dm->probs[Nds].ds = ds;
5346: return(0);
5347: }
5349: /*@
5350: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5352: Not collective
5354: Input Parameters:
5355: + dm - The DM
5356: - num - The region number, in [0, Nds)
5358: Output Parameters:
5359: + label - The region label, or NULL
5360: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5361: - ds - The PetscDS defined on the given region, or NULL
5363: Level: advanced
5365: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5366: @*/
5367: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5368: {
5369: PetscInt Nds;
5374: DMGetNumDS(dm, &Nds);
5375: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5376: if (label) {
5378: *label = dm->probs[num].label;
5379: }
5380: if (fields) {
5382: *fields = dm->probs[num].fields;
5383: }
5384: if (ds) {
5386: *ds = dm->probs[num].ds;
5387: }
5388: return(0);
5389: }
5391: /*@
5392: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5394: Not collective
5396: Input Parameters:
5397: + dm - The DM
5398: . num - The region number, in [0, Nds)
5399: . label - The region label, or NULL
5400: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5401: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5403: Level: advanced
5405: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5406: @*/
5407: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5408: {
5409: PetscInt Nds;
5415: DMGetNumDS(dm, &Nds);
5416: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5417: PetscObjectReference((PetscObject) label);
5418: DMLabelDestroy(&dm->probs[num].label);
5419: dm->probs[num].label = label;
5420: if (fields) {
5422: PetscObjectReference((PetscObject) fields);
5423: ISDestroy(&dm->probs[num].fields);
5424: dm->probs[num].fields = fields;
5425: }
5426: if (ds) {
5428: PetscObjectReference((PetscObject) ds);
5429: PetscDSDestroy(&dm->probs[num].ds);
5430: dm->probs[num].ds = ds;
5431: }
5432: return(0);
5433: }
5435: /*@
5436: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5438: Not collective
5440: Input Parameters:
5441: + dm - The DM
5442: - ds - The PetscDS defined on the given region
5444: Output Parameter:
5445: . num - The region number, in [0, Nds), or -1 if not found
5447: Level: advanced
5449: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5450: @*/
5451: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5452: {
5453: PetscInt Nds, n;
5460: DMGetNumDS(dm, &Nds);
5461: for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5462: if (n >= Nds) *num = -1;
5463: else *num = n;
5464: return(0);
5465: }
5467: /*@
5468: DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5470: Collective on dm
5472: Input Parameter:
5473: . dm - The DM
5475: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5477: Level: intermediate
5479: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5480: @*/
5481: PetscErrorCode DMCreateDS(DM dm)
5482: {
5483: MPI_Comm comm;
5484: PetscDS dsDef;
5485: DMLabel *labelSet;
5486: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5487: PetscBool doSetup = PETSC_TRUE, flg;
5492: if (!dm->fields) return(0);
5493: PetscObjectGetComm((PetscObject) dm, &comm);
5494: DMGetCoordinateDim(dm, &dE);
5495: /* Determine how many regions we have */
5496: PetscMalloc1(Nf, &labelSet);
5497: Nl = 0;
5498: Ndef = 0;
5499: for (f = 0; f < Nf; ++f) {
5500: DMLabel label = dm->fields[f].label;
5501: PetscInt l;
5503: if (!label) {++Ndef; continue;}
5504: for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5505: if (l < Nl) continue;
5506: labelSet[Nl++] = label;
5507: }
5508: /* Create default DS if there are no labels to intersect with */
5509: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5510: if (!dsDef && Ndef && !Nl) {
5511: IS fields;
5512: PetscInt *fld, nf;
5514: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5515: if (nf) {
5516: PetscMalloc1(nf, &fld);
5517: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5518: ISCreate(PETSC_COMM_SELF, &fields);
5519: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5520: ISSetType(fields, ISGENERAL);
5521: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5523: PetscDSCreate(comm, &dsDef);
5524: DMSetRegionDS(dm, NULL, fields, dsDef);
5525: PetscDSDestroy(&dsDef);
5526: ISDestroy(&fields);
5527: }
5528: }
5529: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5530: if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5531: /* Intersect labels with default fields */
5532: if (Ndef && Nl) {
5533: DM plex;
5534: DMLabel cellLabel;
5535: IS fieldIS, allcellIS, defcellIS = NULL;
5536: PetscInt *fields;
5537: const PetscInt *cells;
5538: PetscInt depth, nf = 0, n, c;
5540: DMConvert(dm, DMPLEX, &plex);
5541: DMPlexGetDepth(plex, &depth);
5542: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5543: if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5544: for (l = 0; l < Nl; ++l) {
5545: DMLabel label = labelSet[l];
5546: IS pointIS;
5548: ISDestroy(&defcellIS);
5549: DMLabelGetStratumIS(label, 1, &pointIS);
5550: ISDifference(allcellIS, pointIS, &defcellIS);
5551: ISDestroy(&pointIS);
5552: }
5553: ISDestroy(&allcellIS);
5555: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5556: ISGetLocalSize(defcellIS, &n);
5557: ISGetIndices(defcellIS, &cells);
5558: for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5559: ISRestoreIndices(defcellIS, &cells);
5560: ISDestroy(&defcellIS);
5561: DMPlexLabelComplete(plex, cellLabel);
5563: PetscMalloc1(Ndef, &fields);
5564: for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5565: ISCreate(PETSC_COMM_SELF, &fieldIS);
5566: PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5567: ISSetType(fieldIS, ISGENERAL);
5568: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5570: PetscDSCreate(comm, &dsDef);
5571: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5572: DMLabelDestroy(&cellLabel);
5573: PetscDSSetCoordinateDimension(dsDef, dE);
5574: PetscDSDestroy(&dsDef);
5575: ISDestroy(&fieldIS);
5576: DMDestroy(&plex);
5577: }
5578: /* Create label DSes
5579: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5580: */
5581: /* TODO Should check that labels are disjoint */
5582: for (l = 0; l < Nl; ++l) {
5583: DMLabel label = labelSet[l];
5584: PetscDS ds;
5585: IS fields;
5586: PetscInt *fld, nf;
5588: PetscDSCreate(comm, &ds);
5589: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5590: PetscMalloc1(nf, &fld);
5591: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5592: ISCreate(PETSC_COMM_SELF, &fields);
5593: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5594: ISSetType(fields, ISGENERAL);
5595: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5596: DMSetRegionDS(dm, label, fields, ds);
5597: ISDestroy(&fields);
5598: PetscDSSetCoordinateDimension(ds, dE);
5599: {
5600: DMPolytopeType ct;
5601: PetscInt lStart, lEnd;
5602: PetscBool isHybridLocal = PETSC_FALSE, isHybrid;
5604: DMLabelGetBounds(label, &lStart, &lEnd);
5605: if (lStart >= 0) {
5606: DMPlexGetCellType(dm, lStart, &ct);
5607: switch (ct) {
5608: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5609: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5610: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5611: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5612: isHybridLocal = PETSC_TRUE;break;
5613: default: break;
5614: }
5615: }
5616: MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5617: PetscDSSetHybrid(ds, isHybrid);
5618: }
5619: PetscDSDestroy(&ds);
5620: }
5621: PetscFree(labelSet);
5622: /* Set fields in DSes */
5623: for (s = 0; s < dm->Nds; ++s) {
5624: PetscDS ds = dm->probs[s].ds;
5625: IS fields = dm->probs[s].fields;
5626: const PetscInt *fld;
5627: PetscInt nf;
5629: ISGetLocalSize(fields, &nf);
5630: ISGetIndices(fields, &fld);
5631: for (f = 0; f < nf; ++f) {
5632: PetscObject disc = dm->fields[fld[f]].disc;
5633: PetscBool isHybrid;
5634: PetscClassId id;
5636: PetscDSGetHybrid(ds, &isHybrid);
5637: /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5638: if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5639: PetscDSSetDiscretization(ds, f, disc);
5640: /* We allow people to have placeholder fields and construct the Section by hand */
5641: PetscObjectGetClassId(disc, &id);
5642: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5643: }
5644: ISRestoreIndices(fields, &fld);
5645: }
5646: /* Allow k-jet tabulation */
5647: PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5648: if (flg) {
5649: for (s = 0; s < dm->Nds; ++s) {
5650: PetscDS ds = dm->probs[s].ds;
5651: PetscInt Nf, f;
5653: PetscDSGetNumFields(ds, &Nf);
5654: for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5655: }
5656: }
5657: /* Setup DSes */
5658: if (doSetup) {
5659: for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5660: }
5661: return(0);
5662: }
5664: /*@
5665: DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5667: Collective on DM
5669: Input Parameters:
5670: + dm - The DM
5671: - time - The time
5673: Output Parameters:
5674: + u - The vector will be filled with exact solution values, or NULL
5675: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5677: Note: The user must call PetscDSSetExactSolution() beforehand
5679: Level: developer
5681: .seealso: PetscDSSetExactSolution()
5682: @*/
5683: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5684: {
5685: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5686: void **ectxs;
5687: PetscInt Nf, Nds, s;
5688: PetscErrorCode ierr;
5694: DMGetNumFields(dm, &Nf);
5695: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5696: DMGetNumDS(dm, &Nds);
5697: for (s = 0; s < Nds; ++s) {
5698: PetscDS ds;
5699: DMLabel label;
5700: IS fieldIS;
5701: const PetscInt *fields, id = 1;
5702: PetscInt dsNf, f;
5704: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5705: PetscDSGetNumFields(ds, &dsNf);
5706: ISGetIndices(fieldIS, &fields);
5707: PetscArrayzero(exacts, Nf);
5708: PetscArrayzero(ectxs, Nf);
5709: if (u) {
5710: for (f = 0; f < dsNf; ++f) {
5711: const PetscInt field = fields[f];
5712: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5713: }
5714: ISRestoreIndices(fieldIS, &fields);
5715: if (label) {
5716: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5717: } else {
5718: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5719: }
5720: }
5721: if (u_t) {
5722: PetscArrayzero(exacts, Nf);
5723: PetscArrayzero(ectxs, Nf);
5724: for (f = 0; f < dsNf; ++f) {
5725: const PetscInt field = fields[f];
5726: PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5727: }
5728: ISRestoreIndices(fieldIS, &fields);
5729: if (label) {
5730: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5731: } else {
5732: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5733: }
5734: }
5735: }
5736: if (u) {
5737: PetscObjectSetName((PetscObject) u, "Exact Solution");
5738: PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5739: }
5740: if (u_t) {
5741: PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5742: PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5743: }
5744: PetscFree2(exacts, ectxs);
5745: return(0);
5746: }
5748: /*@
5749: DMCopyDS - Copy the discrete systems for the DM into another DM
5751: Collective on dm
5753: Input Parameter:
5754: . dm - The DM
5756: Output Parameter:
5757: . newdm - The DM
5759: Level: advanced
5761: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5762: @*/
5763: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5764: {
5765: PetscInt Nds, s;
5769: if (dm == newdm) return(0);
5770: DMGetNumDS(dm, &Nds);
5771: DMClearDS(newdm);
5772: for (s = 0; s < Nds; ++s) {
5773: DMLabel label;
5774: IS fields;
5775: PetscDS ds;
5776: PetscInt Nbd, bd;
5778: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5779: DMSetRegionDS(newdm, label, fields, ds);
5780: PetscDSGetNumBoundary(ds, &Nbd);
5781: for (bd = 0; bd < Nbd; ++bd) {
5782: const char *labelname, *name;
5783: PetscInt field;
5785: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5786: PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5787: DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5788: }
5789: }
5790: return(0);
5791: }
5793: /*@
5794: DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5796: Collective on dm
5798: Input Parameter:
5799: . dm - The DM
5801: Output Parameter:
5802: . newdm - The DM
5804: Level: advanced
5806: .seealso: DMCopyFields(), DMCopyDS()
5807: @*/
5808: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5809: {
5813: DMCopyFields(dm, newdm);
5814: DMCopyDS(dm, newdm);
5815: return(0);
5816: }
5818: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5819: {
5820: DM dm_coord,dmc_coord;
5822: Vec coords,ccoords;
5823: Mat inject;
5825: DMGetCoordinateDM(dm,&dm_coord);
5826: DMGetCoordinateDM(dmc,&dmc_coord);
5827: DMGetCoordinates(dm,&coords);
5828: DMGetCoordinates(dmc,&ccoords);
5829: if (coords && !ccoords) {
5830: DMCreateGlobalVector(dmc_coord,&ccoords);
5831: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5832: DMCreateInjection(dmc_coord,dm_coord,&inject);
5833: MatRestrict(inject,coords,ccoords);
5834: MatDestroy(&inject);
5835: DMSetCoordinates(dmc,ccoords);
5836: VecDestroy(&ccoords);
5837: }
5838: return(0);
5839: }
5841: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5842: {
5843: DM dm_coord,subdm_coord;
5845: Vec coords,ccoords,clcoords;
5846: VecScatter *scat_i,*scat_g;
5848: DMGetCoordinateDM(dm,&dm_coord);
5849: DMGetCoordinateDM(subdm,&subdm_coord);
5850: DMGetCoordinates(dm,&coords);
5851: DMGetCoordinates(subdm,&ccoords);
5852: if (coords && !ccoords) {
5853: DMCreateGlobalVector(subdm_coord,&ccoords);
5854: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5855: DMCreateLocalVector(subdm_coord,&clcoords);
5856: PetscObjectSetName((PetscObject)clcoords,"coordinates");
5857: DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5858: VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5859: VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5860: VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5861: VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5862: DMSetCoordinates(subdm,ccoords);
5863: DMSetCoordinatesLocal(subdm,clcoords);
5864: VecScatterDestroy(&scat_i[0]);
5865: VecScatterDestroy(&scat_g[0]);
5866: VecDestroy(&ccoords);
5867: VecDestroy(&clcoords);
5868: PetscFree(scat_i);
5869: PetscFree(scat_g);
5870: }
5871: return(0);
5872: }
5874: /*@
5875: DMGetDimension - Return the topological dimension of the DM
5877: Not collective
5879: Input Parameter:
5880: . dm - The DM
5882: Output Parameter:
5883: . dim - The topological dimension
5885: Level: beginner
5887: .seealso: DMSetDimension(), DMCreate()
5888: @*/
5889: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5890: {
5894: *dim = dm->dim;
5895: return(0);
5896: }
5898: /*@
5899: DMSetDimension - Set the topological dimension of the DM
5901: Collective on dm
5903: Input Parameters:
5904: + dm - The DM
5905: - dim - The topological dimension
5907: Level: beginner
5909: .seealso: DMGetDimension(), DMCreate()
5910: @*/
5911: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5912: {
5913: PetscDS ds;
5919: dm->dim = dim;
5920: DMGetDS(dm, &ds);
5921: if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5922: return(0);
5923: }
5925: /*@
5926: DMGetDimPoints - Get the half-open interval for all points of a given dimension
5928: Collective on dm
5930: Input Parameters:
5931: + dm - the DM
5932: - dim - the dimension
5934: Output Parameters:
5935: + pStart - The first point of the given dimension
5936: - pEnd - The first point following points of the given dimension
5938: Note:
5939: The points are vertices in the Hasse diagram encoding the topology. This is explained in
5940: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5941: then the interval is empty.
5943: Level: intermediate
5945: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5946: @*/
5947: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5948: {
5949: PetscInt d;
5954: DMGetDimension(dm, &d);
5955: if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5956: if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5957: (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5958: return(0);
5959: }
5961: /*@
5962: DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5964: Collective on dm
5966: Input Parameters:
5967: + dm - the DM
5968: - c - coordinate vector
5970: Notes:
5971: The coordinates do include those for ghost points, which are in the local vector.
5973: The vector c should be destroyed by the caller.
5975: Level: intermediate
5977: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
5978: @*/
5979: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5980: {
5986: PetscObjectReference((PetscObject) c);
5987: VecDestroy(&dm->coordinates);
5988: dm->coordinates = c;
5989: VecDestroy(&dm->coordinatesLocal);
5990: DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5991: DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5992: return(0);
5993: }
5995: /*@
5996: DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5998: Not collective
6000: Input Parameters:
6001: + dm - the DM
6002: - c - coordinate vector
6004: Notes:
6005: The coordinates of ghost points can be set using DMSetCoordinates()
6006: followed by DMGetCoordinatesLocal(). This is intended to enable the
6007: setting of ghost coordinates outside of the domain.
6009: The vector c should be destroyed by the caller.
6011: Level: intermediate
6013: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6014: @*/
6015: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6016: {
6022: PetscObjectReference((PetscObject) c);
6023: VecDestroy(&dm->coordinatesLocal);
6025: dm->coordinatesLocal = c;
6027: VecDestroy(&dm->coordinates);
6028: return(0);
6029: }
6031: /*@
6032: DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
6034: Collective on dm
6036: Input Parameter:
6037: . dm - the DM
6039: Output Parameter:
6040: . c - global coordinate vector
6042: Note:
6043: This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6044: destroyed the array will no longer be valid.
6046: Each process has only the local coordinates (does NOT have the ghost coordinates).
6048: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6049: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6051: Level: intermediate
6053: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6054: @*/
6055: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6056: {
6062: if (!dm->coordinates && dm->coordinatesLocal) {
6063: DM cdm = NULL;
6064: PetscBool localized;
6066: DMGetCoordinateDM(dm, &cdm);
6067: DMCreateGlobalVector(cdm, &dm->coordinates);
6068: DMGetCoordinatesLocalized(dm, &localized);
6069: /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6070: if (localized) {
6071: PetscInt cdim;
6073: DMGetCoordinateDim(dm, &cdim);
6074: VecSetBlockSize(dm->coordinates, cdim);
6075: }
6076: PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6077: DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6078: DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6079: }
6080: *c = dm->coordinates;
6081: return(0);
6082: }
6084: /*@
6085: DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6087: Collective on dm
6089: Input Parameter:
6090: . dm - the DM
6092: Level: advanced
6094: .seealso: DMGetCoordinatesLocalNoncollective()
6095: @*/
6096: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6097: {
6102: if (!dm->coordinatesLocal && dm->coordinates) {
6103: DM cdm = NULL;
6104: PetscBool localized;
6106: DMGetCoordinateDM(dm, &cdm);
6107: DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6108: DMGetCoordinatesLocalized(dm, &localized);
6109: /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6110: if (localized) {
6111: PetscInt cdim;
6113: DMGetCoordinateDim(dm, &cdim);
6114: VecSetBlockSize(dm->coordinates, cdim);
6115: }
6116: PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6117: DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6118: DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6119: }
6120: return(0);
6121: }
6123: /*@
6124: DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6126: Collective on dm
6128: Input Parameter:
6129: . dm - the DM
6131: Output Parameter:
6132: . c - coordinate vector
6134: Note:
6135: This is a borrowed reference, so the user should NOT 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: intermediate
6144: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6145: @*/
6146: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6147: {
6153: DMGetCoordinatesLocalSetUp(dm);
6154: *c = dm->coordinatesLocal;
6155: return(0);
6156: }
6158: /*@
6159: DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6161: Not collective
6163: Input Parameter:
6164: . dm - the DM
6166: Output Parameter:
6167: . c - coordinate vector
6169: Level: advanced
6171: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6172: @*/
6173: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6174: {
6178: if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6179: *c = dm->coordinatesLocal;
6180: return(0);
6181: }
6183: /*@
6184: DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6186: Not collective
6188: Input Parameter:
6189: + dm - the DM
6190: - p - the IS of points whose coordinates will be returned
6192: Output Parameter:
6193: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6194: - pCoord - the Vec with coordinates of points in p
6196: Note:
6197: DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6199: This creates a new vector, so the user SHOULD destroy this vector
6201: Each process has the local and ghost coordinates
6203: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6204: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6206: Level: advanced
6208: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6209: @*/
6210: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6211: {
6212: PetscSection cs, newcs;
6213: Vec coords;
6214: const PetscScalar *arr;
6215: PetscScalar *newarr=NULL;
6216: PetscInt n;
6217: PetscErrorCode ierr;
6224: if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6225: if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6226: cs = dm->coordinateDM->localSection;
6227: coords = dm->coordinatesLocal;
6228: VecGetArrayRead(coords, &arr);
6229: PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6230: VecRestoreArrayRead(coords, &arr);
6231: if (pCoord) {
6232: PetscSectionGetStorageSize(newcs, &n);
6233: /* set array in two steps to mimic PETSC_OWN_POINTER */
6234: VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6235: VecReplaceArray(*pCoord, newarr);
6236: } else {
6237: PetscFree(newarr);
6238: }
6239: if (pCoordSection) {*pCoordSection = newcs;}
6240: else {PetscSectionDestroy(&newcs);}
6241: return(0);
6242: }
6244: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6245: {
6251: if (!dm->coordinateField) {
6252: if (dm->ops->createcoordinatefield) {
6253: (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6254: }
6255: }
6256: *field = dm->coordinateField;
6257: return(0);
6258: }
6260: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6261: {
6267: PetscObjectReference((PetscObject)field);
6268: DMFieldDestroy(&dm->coordinateField);
6269: dm->coordinateField = field;
6270: return(0);
6271: }
6273: /*@
6274: DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6276: Collective on dm
6278: Input Parameter:
6279: . dm - the DM
6281: Output Parameter:
6282: . cdm - coordinate DM
6284: Level: intermediate
6286: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6287: @*/
6288: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6289: {
6295: if (!dm->coordinateDM) {
6296: DM cdm;
6298: if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6299: (*dm->ops->createcoordinatedm)(dm, &cdm);
6300: /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6301: * until the call to CreateCoordinateDM) */
6302: DMDestroy(&dm->coordinateDM);
6303: dm->coordinateDM = cdm;
6304: }
6305: *cdm = dm->coordinateDM;
6306: return(0);
6307: }
6309: /*@
6310: DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6312: Logically Collective on dm
6314: Input Parameters:
6315: + dm - the DM
6316: - cdm - coordinate DM
6318: Level: intermediate
6320: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6321: @*/
6322: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6323: {
6329: PetscObjectReference((PetscObject)cdm);
6330: DMDestroy(&dm->coordinateDM);
6331: dm->coordinateDM = cdm;
6332: return(0);
6333: }
6335: /*@
6336: DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6338: Not Collective
6340: Input Parameter:
6341: . dm - The DM object
6343: Output Parameter:
6344: . dim - The embedding dimension
6346: Level: intermediate
6348: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6349: @*/
6350: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6351: {
6355: if (dm->dimEmbed == PETSC_DEFAULT) {
6356: dm->dimEmbed = dm->dim;
6357: }
6358: *dim = dm->dimEmbed;
6359: return(0);
6360: }
6362: /*@
6363: DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6365: Not Collective
6367: Input Parameters:
6368: + dm - The DM object
6369: - dim - The embedding dimension
6371: Level: intermediate
6373: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6374: @*/
6375: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6376: {
6377: PetscDS ds;
6382: dm->dimEmbed = dim;
6383: DMGetDS(dm, &ds);
6384: PetscDSSetCoordinateDimension(ds, dim);
6385: return(0);
6386: }
6388: /*@
6389: DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6391: Collective on dm
6393: Input Parameter:
6394: . dm - The DM object
6396: Output Parameter:
6397: . section - The PetscSection object
6399: Level: intermediate
6401: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6402: @*/
6403: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6404: {
6405: DM cdm;
6411: DMGetCoordinateDM(dm, &cdm);
6412: DMGetLocalSection(cdm, section);
6413: return(0);
6414: }
6416: /*@
6417: DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6419: Not Collective
6421: Input Parameters:
6422: + dm - The DM object
6423: . dim - The embedding dimension, or PETSC_DETERMINE
6424: - section - The PetscSection object
6426: Level: intermediate
6428: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6429: @*/
6430: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6431: {
6432: DM cdm;
6438: DMGetCoordinateDM(dm, &cdm);
6439: DMSetLocalSection(cdm, section);
6440: if (dim == PETSC_DETERMINE) {
6441: PetscInt d = PETSC_DEFAULT;
6442: PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6444: PetscSectionGetChart(section, &pStart, &pEnd);
6445: DMGetDimPoints(dm, 0, &vStart, &vEnd);
6446: pStart = PetscMax(vStart, pStart);
6447: pEnd = PetscMin(vEnd, pEnd);
6448: for (v = pStart; v < pEnd; ++v) {
6449: PetscSectionGetDof(section, v, &dd);
6450: if (dd) {d = dd; break;}
6451: }
6452: if (d >= 0) {DMSetCoordinateDim(dm, d);}
6453: }
6454: return(0);
6455: }
6457: /*@
6458: DMProjectCoordinates - Project coordinates to a different space
6460: Input Parameters:
6461: + dm - The DM object
6462: - disc - The new coordinate discretization
6464: Level: intermediate
6466: .seealso: DMGetCoordinateField()
6467: @*/
6468: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6469: {
6470: PetscObject discOld;
6471: PetscClassId classid;
6472: DM cdmOld,cdmNew;
6473: Vec coordsOld,coordsNew;
6474: Mat matInterp;
6481: DMGetCoordinateDM(dm, &cdmOld);
6482: /* Check current discretization is compatible */
6483: DMGetField(cdmOld, 0, NULL, &discOld);
6484: PetscObjectGetClassId(discOld, &classid);
6485: if (classid != PETSCFE_CLASSID) {
6486: if (classid == PETSC_CONTAINER_CLASSID) {
6487: PetscFE feLinear;
6488: DMPolytopeType ct;
6489: PetscInt dim, dE, cStart;
6490: PetscBool simplex;
6492: /* Assume linear vertex coordinates */
6493: DMGetDimension(dm, &dim);
6494: DMGetCoordinateDim(dm, &dE);
6495: DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6496: DMPlexGetCellType(dm, cStart, &ct);
6497: switch (ct) {
6498: case DM_POLYTOPE_TRI_PRISM:
6499: case DM_POLYTOPE_TRI_PRISM_TENSOR:
6500: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6501: default: break;
6502: }
6503: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6504: PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6505: DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6506: PetscFEDestroy(&feLinear);
6507: DMCreateDS(cdmOld);
6508: } else {
6509: const char *discname;
6511: PetscObjectGetType(discOld, &discname);
6512: SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6513: }
6514: }
6515: /* Make a fresh clone of the coordinate DM */
6516: DMClone(cdmOld, &cdmNew);
6517: DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6518: DMCreateDS(cdmNew);
6519: /* Project the coordinate vector from old to new space */
6520: DMGetCoordinates(dm, &coordsOld);
6521: DMCreateGlobalVector(cdmNew, &coordsNew);
6522: DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6523: MatInterpolate(matInterp, coordsOld, coordsNew);
6524: MatDestroy(&matInterp);
6525: /* Set new coordinate structures */
6526: DMSetCoordinateField(dm, NULL);
6527: DMSetCoordinateDM(dm, cdmNew);
6528: DMSetCoordinates(dm, coordsNew);
6529: VecDestroy(&coordsNew);
6530: DMDestroy(&cdmNew);
6531: return(0);
6532: }
6534: /*@C
6535: DMGetPeriodicity - Get the description of mesh periodicity
6537: Input Parameters:
6538: . dm - The DM object
6540: Output Parameters:
6541: + per - Whether the DM is periodic or not
6542: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6543: . L - If we assume the mesh is a torus, this is the length of each coordinate
6544: - bd - This describes the type of periodicity in each topological dimension
6546: Level: developer
6548: .seealso: DMGetPeriodicity()
6549: @*/
6550: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6551: {
6554: if (per) *per = dm->periodic;
6555: if (L) *L = dm->L;
6556: if (maxCell) *maxCell = dm->maxCell;
6557: if (bd) *bd = dm->bdtype;
6558: return(0);
6559: }
6561: /*@C
6562: DMSetPeriodicity - Set the description of mesh periodicity
6564: Input Parameters:
6565: + dm - The DM object
6566: . per - Whether the DM is periodic or not.
6567: . 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.
6568: . L - If we assume the mesh is a torus, this is the length of each coordinate
6569: - bd - This describes the type of periodicity in each topological dimension
6571: 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.
6573: Level: developer
6575: .seealso: DMGetPeriodicity()
6576: @*/
6577: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6578: {
6579: PetscInt dim, d;
6588: DMGetDimension(dm, &dim);
6589: if (maxCell) {
6590: if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6591: for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6592: } else { /* remove maxCell information to disable automatic computation of localized vertices */
6593: PetscFree(dm->maxCell);
6594: }
6596: if (L) {
6597: if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6598: for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6599: }
6600: if (bd) {
6601: if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6602: for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6603: }
6604: dm->periodic = per;
6605: return(0);
6606: }
6608: /*@
6609: 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.
6611: Input Parameters:
6612: + dm - The DM
6613: . in - The input coordinate point (dim numbers)
6614: - endpoint - Include the endpoint L_i
6616: Output Parameter:
6617: . out - The localized coordinate point
6619: Level: developer
6621: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6622: @*/
6623: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6624: {
6625: PetscInt dim, d;
6629: DMGetCoordinateDim(dm, &dim);
6630: if (!dm->maxCell) {
6631: for (d = 0; d < dim; ++d) out[d] = in[d];
6632: } else {
6633: if (endpoint) {
6634: for (d = 0; d < dim; ++d) {
6635: 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)) {
6636: out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6637: } else {
6638: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6639: }
6640: }
6641: } else {
6642: for (d = 0; d < dim; ++d) {
6643: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6644: }
6645: }
6646: }
6647: return(0);
6648: }
6650: /*
6651: 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.
6653: Input Parameters:
6654: + dm - The DM
6655: . dim - The spatial dimension
6656: . anchor - The anchor point, the input point can be no more than maxCell away from it
6657: - in - The input coordinate point (dim numbers)
6659: Output Parameter:
6660: . out - The localized coordinate point
6662: Level: developer
6664: 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
6666: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6667: */
6668: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6669: {
6670: PetscInt d;
6673: if (!dm->maxCell) {
6674: for (d = 0; d < dim; ++d) out[d] = in[d];
6675: } else {
6676: for (d = 0; d < dim; ++d) {
6677: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6678: out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6679: } else {
6680: out[d] = in[d];
6681: }
6682: }
6683: }
6684: return(0);
6685: }
6687: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6688: {
6689: PetscInt d;
6692: if (!dm->maxCell) {
6693: for (d = 0; d < dim; ++d) out[d] = in[d];
6694: } else {
6695: for (d = 0; d < dim; ++d) {
6696: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6697: out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6698: } else {
6699: out[d] = in[d];
6700: }
6701: }
6702: }
6703: return(0);
6704: }
6706: /*
6707: 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.
6709: Input Parameters:
6710: + dm - The DM
6711: . dim - The spatial dimension
6712: . anchor - The anchor point, the input point can be no more than maxCell away from it
6713: . in - The input coordinate delta (dim numbers)
6714: - out - The input coordinate point (dim numbers)
6716: Output Parameter:
6717: . out - The localized coordinate in + out
6719: Level: developer
6721: 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
6723: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6724: */
6725: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6726: {
6727: PetscInt d;
6730: if (!dm->maxCell) {
6731: for (d = 0; d < dim; ++d) out[d] += in[d];
6732: } else {
6733: for (d = 0; d < dim; ++d) {
6734: const PetscReal maxC = dm->maxCell[d];
6736: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6737: const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6739: if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6740: 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]));
6741: out[d] += newCoord;
6742: } else {
6743: out[d] += in[d];
6744: }
6745: }
6746: }
6747: return(0);
6748: }
6750: /*@
6751: DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6753: Not collective
6755: Input Parameter:
6756: . dm - The DM
6758: Output Parameter:
6759: areLocalized - True if localized
6761: Level: developer
6763: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6764: @*/
6765: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6766: {
6767: DM cdm;
6768: PetscSection coordSection;
6769: PetscInt cStart, cEnd, sStart, sEnd, c, dof;
6770: PetscBool isPlex, alreadyLocalized;
6776: *areLocalized = PETSC_FALSE;
6778: /* We need some generic way of refering to cells/vertices */
6779: DMGetCoordinateDM(dm, &cdm);
6780: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6781: if (!isPlex) return(0);
6783: DMGetCoordinateSection(dm, &coordSection);
6784: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6785: PetscSectionGetChart(coordSection, &sStart, &sEnd);
6786: alreadyLocalized = PETSC_FALSE;
6787: for (c = cStart; c < cEnd; ++c) {
6788: if (c < sStart || c >= sEnd) continue;
6789: PetscSectionGetDof(coordSection, c, &dof);
6790: if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6791: }
6792: *areLocalized = alreadyLocalized;
6793: return(0);
6794: }
6796: /*@
6797: DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6799: Collective on dm
6801: Input Parameter:
6802: . dm - The DM
6804: Output Parameter:
6805: areLocalized - True if localized
6807: Level: developer
6809: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6810: @*/
6811: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6812: {
6813: PetscBool localized;
6819: DMGetCoordinatesLocalizedLocal(dm,&localized);
6820: MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6821: return(0);
6822: }
6824: /*@
6825: DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6827: Collective on dm
6829: Input Parameter:
6830: . dm - The DM
6832: Level: developer
6834: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6835: @*/
6836: PetscErrorCode DMLocalizeCoordinates(DM dm)
6837: {
6838: DM cdm;
6839: PetscSection coordSection, cSection;
6840: Vec coordinates, cVec;
6841: PetscScalar *coords, *coords2, *anchor, *localized;
6842: PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6843: PetscBool alreadyLocalized, alreadyLocalizedGlobal;
6844: PetscInt maxHeight = 0, h;
6845: PetscInt *pStart = NULL, *pEnd = NULL;
6850: if (!dm->periodic) return(0);
6851: DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6852: if (alreadyLocalized) return(0);
6854: /* We need some generic way of refering to cells/vertices */
6855: DMGetCoordinateDM(dm, &cdm);
6856: {
6857: PetscBool isplex;
6859: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6860: if (isplex) {
6861: DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6862: DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6863: DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6864: pEnd = &pStart[maxHeight + 1];
6865: newStart = vStart;
6866: newEnd = vEnd;
6867: for (h = 0; h <= maxHeight; h++) {
6868: DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6869: newStart = PetscMin(newStart,pStart[h]);
6870: newEnd = PetscMax(newEnd,pEnd[h]);
6871: }
6872: } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6873: }
6874: DMGetCoordinatesLocal(dm, &coordinates);
6875: if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6876: DMGetCoordinateSection(dm, &coordSection);
6877: VecGetBlockSize(coordinates, &bs);
6878: PetscSectionGetChart(coordSection,&sStart,&sEnd);
6880: PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6881: PetscSectionSetNumFields(cSection, 1);
6882: PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6883: PetscSectionSetFieldComponents(cSection, 0, Nc);
6884: PetscSectionSetChart(cSection, newStart, newEnd);
6886: DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6887: localized = &anchor[bs];
6888: alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6889: for (h = 0; h <= maxHeight; h++) {
6890: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6892: for (c = cStart; c < cEnd; ++c) {
6893: PetscScalar *cellCoords = NULL;
6894: PetscInt b;
6896: if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6897: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6898: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6899: for (d = 0; d < dof/bs; ++d) {
6900: DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6901: for (b = 0; b < bs; b++) {
6902: if (cellCoords[d*bs + b] != localized[b]) break;
6903: }
6904: if (b < bs) break;
6905: }
6906: if (d < dof/bs) {
6907: if (c >= sStart && c < sEnd) {
6908: PetscInt cdof;
6910: PetscSectionGetDof(coordSection, c, &cdof);
6911: if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6912: }
6913: PetscSectionSetDof(cSection, c, dof);
6914: PetscSectionSetFieldDof(cSection, c, 0, dof);
6915: }
6916: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6917: }
6918: }
6919: MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6920: if (alreadyLocalizedGlobal) {
6921: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6922: PetscSectionDestroy(&cSection);
6923: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6924: return(0);
6925: }
6926: for (v = vStart; v < vEnd; ++v) {
6927: PetscSectionGetDof(coordSection, v, &dof);
6928: PetscSectionSetDof(cSection, v, dof);
6929: PetscSectionSetFieldDof(cSection, v, 0, dof);
6930: }
6931: PetscSectionSetUp(cSection);
6932: PetscSectionGetStorageSize(cSection, &coordSize);
6933: VecCreate(PETSC_COMM_SELF, &cVec);
6934: PetscObjectSetName((PetscObject)cVec,"coordinates");
6935: VecSetBlockSize(cVec, bs);
6936: VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6937: VecSetType(cVec, VECSTANDARD);
6938: VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6939: VecGetArray(cVec, &coords2);
6940: for (v = vStart; v < vEnd; ++v) {
6941: PetscSectionGetDof(coordSection, v, &dof);
6942: PetscSectionGetOffset(coordSection, v, &off);
6943: PetscSectionGetOffset(cSection, v, &off2);
6944: for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6945: }
6946: for (h = 0; h <= maxHeight; h++) {
6947: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6949: for (c = cStart; c < cEnd; ++c) {
6950: PetscScalar *cellCoords = NULL;
6951: PetscInt b, cdof;
6953: PetscSectionGetDof(cSection,c,&cdof);
6954: if (!cdof) continue;
6955: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6956: PetscSectionGetOffset(cSection, c, &off2);
6957: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6958: for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6959: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6960: }
6961: }
6962: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6963: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6964: VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6965: VecRestoreArray(cVec, &coords2);
6966: DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6967: DMSetCoordinatesLocal(dm, cVec);
6968: VecDestroy(&cVec);
6969: PetscSectionDestroy(&cSection);
6970: return(0);
6971: }
6973: /*@
6974: DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6976: Collective on v (see explanation below)
6978: Input Parameters:
6979: + dm - The DM
6980: . v - The Vec of points
6981: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6982: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6984: Output Parameter:
6985: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6986: - cells - The PetscSF containing the ranks and local indices of the containing points.
6989: Level: developer
6991: Notes:
6992: To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6993: To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6995: If *cellSF is NULL on input, a PetscSF will be created.
6996: If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6998: An array that maps each point to its containing cell can be obtained with
7000: $ const PetscSFNode *cells;
7001: $ PetscInt nFound;
7002: $ const PetscInt *found;
7003: $
7004: $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
7006: Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7007: the index of the cell in its rank's local numbering.
7009: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7010: @*/
7011: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7012: {
7019: if (*cellSF) {
7020: PetscMPIInt result;
7023: MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7024: if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7025: } else {
7026: PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7027: }
7028: if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7029: PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7030: (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7031: PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7032: return(0);
7033: }
7035: /*@
7036: DMGetOutputDM - Retrieve the DM associated with the layout for output
7038: Collective on dm
7040: Input Parameter:
7041: . dm - The original DM
7043: Output Parameter:
7044: . odm - The DM which provides the layout for output
7046: Level: intermediate
7048: .seealso: VecView(), DMGetGlobalSection()
7049: @*/
7050: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7051: {
7052: PetscSection section;
7053: PetscBool hasConstraints, ghasConstraints;
7059: DMGetLocalSection(dm, §ion);
7060: PetscSectionHasConstraints(section, &hasConstraints);
7061: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7062: if (!ghasConstraints) {
7063: *odm = dm;
7064: return(0);
7065: }
7066: if (!dm->dmBC) {
7067: PetscSection newSection, gsection;
7068: PetscSF sf;
7070: DMClone(dm, &dm->dmBC);
7071: DMCopyDisc(dm, dm->dmBC);
7072: PetscSectionClone(section, &newSection);
7073: DMSetLocalSection(dm->dmBC, newSection);
7074: PetscSectionDestroy(&newSection);
7075: DMGetPointSF(dm->dmBC, &sf);
7076: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7077: DMSetGlobalSection(dm->dmBC, gsection);
7078: PetscSectionDestroy(&gsection);
7079: }
7080: *odm = dm->dmBC;
7081: return(0);
7082: }
7084: /*@
7085: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7087: Input Parameter:
7088: . dm - The original DM
7090: Output Parameters:
7091: + num - The output sequence number
7092: - val - The output sequence value
7094: Level: intermediate
7096: Note: This is intended for output that should appear in sequence, for instance
7097: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7099: .seealso: VecView()
7100: @*/
7101: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7102: {
7107: return(0);
7108: }
7110: /*@
7111: DMSetOutputSequenceNumber - Set the sequence number/value for output
7113: Input Parameters:
7114: + dm - The original DM
7115: . num - The output sequence number
7116: - val - The output sequence value
7118: Level: intermediate
7120: Note: This is intended for output that should appear in sequence, for instance
7121: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7123: .seealso: VecView()
7124: @*/
7125: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7126: {
7129: dm->outputSequenceNum = num;
7130: dm->outputSequenceVal = val;
7131: return(0);
7132: }
7134: /*@C
7135: DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7137: Input Parameters:
7138: + dm - The original DM
7139: . name - The sequence name
7140: - num - The output sequence number
7142: Output Parameter:
7143: . val - The output sequence value
7145: Level: intermediate
7147: Note: This is intended for output that should appear in sequence, for instance
7148: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7150: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7151: @*/
7152: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7153: {
7154: PetscBool ishdf5;
7161: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7162: if (ishdf5) {
7163: #if defined(PETSC_HAVE_HDF5)
7164: PetscScalar value;
7166: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7167: *val = PetscRealPart(value);
7168: #endif
7169: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7170: return(0);
7171: }
7173: /*@
7174: DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7176: Not collective
7178: Input Parameter:
7179: . dm - The DM
7181: Output Parameter:
7182: . useNatural - The flag to build the mapping to a natural order during distribution
7184: Level: beginner
7186: .seealso: DMSetUseNatural(), DMCreate()
7187: @*/
7188: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7189: {
7193: *useNatural = dm->useNatural;
7194: return(0);
7195: }
7197: /*@
7198: DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7200: Collective on dm
7202: Input Parameters:
7203: + dm - The DM
7204: - useNatural - The flag to build the mapping to a natural order during distribution
7206: Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7208: Level: beginner
7210: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7211: @*/
7212: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7213: {
7217: dm->useNatural = useNatural;
7218: return(0);
7219: }
7222: /*@C
7223: DMCreateLabel - Create a label of the given name if it does not already exist
7225: Not Collective
7227: Input Parameters:
7228: + dm - The DM object
7229: - name - The label name
7231: Level: intermediate
7233: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7234: @*/
7235: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7236: {
7237: PetscBool flg;
7238: DMLabel label;
7244: DMHasLabel(dm, name, &flg);
7245: if (!flg) {
7246: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7247: DMAddLabel(dm, label);
7248: DMLabelDestroy(&label);
7249: }
7250: return(0);
7251: }
7253: /*@C
7254: DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.
7256: Not Collective
7258: Input Parameters:
7259: + dm - The DM object
7260: . l - The index for the label
7261: - name - The label name
7263: Level: intermediate
7265: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7266: @*/
7267: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7268: {
7269: DMLabelLink orig, prev = NULL;
7270: DMLabel label;
7271: PetscInt Nl, m;
7272: PetscBool flg, match;
7273: const char *lname;
7279: DMHasLabel(dm, name, &flg);
7280: if (!flg) {
7281: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7282: DMAddLabel(dm, label);
7283: DMLabelDestroy(&label);
7284: }
7285: DMGetNumLabels(dm, &Nl);
7286: if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7287: for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7288: PetscObjectGetName((PetscObject) orig->label, &lname);
7289: PetscStrcmp(name, lname, &match);
7290: if (match) break;
7291: }
7292: if (m == l) return(0);
7293: if (!m) dm->labels = orig->next;
7294: else prev->next = orig->next;
7295: if (!l) {
7296: orig->next = dm->labels;
7297: dm->labels = orig;
7298: } else {
7299: for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7300: orig->next = prev->next;
7301: prev->next = orig;
7302: }
7303: return(0);
7304: }
7306: /*@C
7307: DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7309: Not Collective
7311: Input Parameters:
7312: + dm - The DM object
7313: . name - The label name
7314: - point - The mesh point
7316: Output Parameter:
7317: . value - The label value for this point, or -1 if the point is not in the label
7319: Level: beginner
7321: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7322: @*/
7323: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7324: {
7325: DMLabel label;
7331: DMGetLabel(dm, name, &label);
7332: if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7333: DMLabelGetValue(label, point, value);
7334: return(0);
7335: }
7337: /*@C
7338: DMSetLabelValue - Add a point to a Sieve Label with given value
7340: Not Collective
7342: Input Parameters:
7343: + dm - The DM object
7344: . name - The label name
7345: . point - The mesh point
7346: - value - The label value for this point
7348: Output Parameter:
7350: Level: beginner
7352: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7353: @*/
7354: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7355: {
7356: DMLabel label;
7362: DMGetLabel(dm, name, &label);
7363: if (!label) {
7364: DMCreateLabel(dm, name);
7365: DMGetLabel(dm, name, &label);
7366: }
7367: DMLabelSetValue(label, point, value);
7368: return(0);
7369: }
7371: /*@C
7372: DMClearLabelValue - Remove a point from a Sieve Label with given value
7374: Not Collective
7376: Input Parameters:
7377: + dm - The DM object
7378: . name - The label name
7379: . point - The mesh point
7380: - value - The label value for this point
7382: Output Parameter:
7384: Level: beginner
7386: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7387: @*/
7388: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7389: {
7390: DMLabel label;
7396: DMGetLabel(dm, name, &label);
7397: if (!label) return(0);
7398: DMLabelClearValue(label, point, value);
7399: return(0);
7400: }
7402: /*@C
7403: DMGetLabelSize - Get the number of different integer ids in a Label
7405: Not Collective
7407: Input Parameters:
7408: + dm - The DM object
7409: - name - The label name
7411: Output Parameter:
7412: . size - The number of different integer ids, or 0 if the label does not exist
7414: Level: beginner
7416: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7417: @*/
7418: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7419: {
7420: DMLabel label;
7427: DMGetLabel(dm, name, &label);
7428: *size = 0;
7429: if (!label) return(0);
7430: DMLabelGetNumValues(label, size);
7431: return(0);
7432: }
7434: /*@C
7435: DMGetLabelIdIS - Get the integer ids in a label
7437: Not Collective
7439: Input Parameters:
7440: + mesh - The DM object
7441: - name - The label name
7443: Output Parameter:
7444: . ids - The integer ids, or NULL if the label does not exist
7446: Level: beginner
7448: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7449: @*/
7450: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7451: {
7452: DMLabel label;
7459: DMGetLabel(dm, name, &label);
7460: *ids = NULL;
7461: if (label) {
7462: DMLabelGetValueIS(label, ids);
7463: } else {
7464: /* returning an empty IS */
7465: ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7466: }
7467: return(0);
7468: }
7470: /*@C
7471: DMGetStratumSize - Get the number of points in a label stratum
7473: Not Collective
7475: Input Parameters:
7476: + dm - The DM object
7477: . name - The label name
7478: - value - The stratum value
7480: Output Parameter:
7481: . size - The stratum size
7483: Level: beginner
7485: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7486: @*/
7487: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7488: {
7489: DMLabel label;
7496: DMGetLabel(dm, name, &label);
7497: *size = 0;
7498: if (!label) return(0);
7499: DMLabelGetStratumSize(label, value, size);
7500: return(0);
7501: }
7503: /*@C
7504: DMGetStratumIS - Get the points in a label stratum
7506: Not Collective
7508: Input Parameters:
7509: + dm - The DM object
7510: . name - The label name
7511: - value - The stratum value
7513: Output Parameter:
7514: . points - The stratum points, or NULL if the label does not exist or does not have that value
7516: Level: beginner
7518: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7519: @*/
7520: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7521: {
7522: DMLabel label;
7529: DMGetLabel(dm, name, &label);
7530: *points = NULL;
7531: if (!label) return(0);
7532: DMLabelGetStratumIS(label, value, points);
7533: return(0);
7534: }
7536: /*@C
7537: DMSetStratumIS - Set the points in a label stratum
7539: Not Collective
7541: Input Parameters:
7542: + dm - The DM object
7543: . name - The label name
7544: . value - The stratum value
7545: - points - The stratum points
7547: Level: beginner
7549: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7550: @*/
7551: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7552: {
7553: DMLabel label;
7560: DMGetLabel(dm, name, &label);
7561: if (!label) return(0);
7562: DMLabelSetStratumIS(label, value, points);
7563: return(0);
7564: }
7566: /*@C
7567: DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7569: Not Collective
7571: Input Parameters:
7572: + dm - The DM object
7573: . name - The label name
7574: - value - The label value for this point
7576: Output Parameter:
7578: Level: beginner
7580: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7581: @*/
7582: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7583: {
7584: DMLabel label;
7590: DMGetLabel(dm, name, &label);
7591: if (!label) return(0);
7592: DMLabelClearStratum(label, value);
7593: return(0);
7594: }
7596: /*@
7597: DMGetNumLabels - Return the number of labels defined by the mesh
7599: Not Collective
7601: Input Parameter:
7602: . dm - The DM object
7604: Output Parameter:
7605: . numLabels - the number of Labels
7607: Level: intermediate
7609: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7610: @*/
7611: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7612: {
7613: DMLabelLink next = dm->labels;
7614: PetscInt n = 0;
7619: while (next) {++n; next = next->next;}
7620: *numLabels = n;
7621: return(0);
7622: }
7624: /*@C
7625: DMGetLabelName - Return the name of nth label
7627: Not Collective
7629: Input Parameters:
7630: + dm - The DM object
7631: - n - the label number
7633: Output Parameter:
7634: . name - the label name
7636: Level: intermediate
7638: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7639: @*/
7640: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7641: {
7642: DMLabelLink next = dm->labels;
7643: PetscInt l = 0;
7649: while (next) {
7650: if (l == n) {
7651: PetscObjectGetName((PetscObject) next->label, name);
7652: return(0);
7653: }
7654: ++l;
7655: next = next->next;
7656: }
7657: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7658: }
7660: /*@C
7661: DMHasLabel - Determine whether the mesh has a label of a given name
7663: Not Collective
7665: Input Parameters:
7666: + dm - The DM object
7667: - name - The label name
7669: Output Parameter:
7670: . hasLabel - PETSC_TRUE if the label is present
7672: Level: intermediate
7674: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7675: @*/
7676: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7677: {
7678: DMLabelLink next = dm->labels;
7679: const char *lname;
7686: *hasLabel = PETSC_FALSE;
7687: while (next) {
7688: PetscObjectGetName((PetscObject) next->label, &lname);
7689: PetscStrcmp(name, lname, hasLabel);
7690: if (*hasLabel) break;
7691: next = next->next;
7692: }
7693: return(0);
7694: }
7696: /*@C
7697: DMGetLabel - Return the label of a given name, or NULL
7699: Not Collective
7701: Input Parameters:
7702: + dm - The DM object
7703: - name - The label name
7705: Output Parameter:
7706: . label - The DMLabel, or NULL if the label is absent
7708: Note: Some of the default labels in a DMPlex will be
7709: $ "depth" - Holds the depth (co-dimension) of each mesh point
7710: $ "celltype" - Holds the topological type of each cell
7711: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7712: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7713: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7714: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7716: Level: intermediate
7718: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7719: @*/
7720: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7721: {
7722: DMLabelLink next = dm->labels;
7723: PetscBool hasLabel;
7724: const char *lname;
7731: *label = NULL;
7732: while (next) {
7733: PetscObjectGetName((PetscObject) next->label, &lname);
7734: PetscStrcmp(name, lname, &hasLabel);
7735: if (hasLabel) {
7736: *label = next->label;
7737: break;
7738: }
7739: next = next->next;
7740: }
7741: return(0);
7742: }
7744: /*@C
7745: DMGetLabelByNum - Return the nth label
7747: Not Collective
7749: Input Parameters:
7750: + dm - The DM object
7751: - n - the label number
7753: Output Parameter:
7754: . label - the label
7756: Level: intermediate
7758: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7759: @*/
7760: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7761: {
7762: DMLabelLink next = dm->labels;
7763: PetscInt l = 0;
7768: while (next) {
7769: if (l == n) {
7770: *label = next->label;
7771: return(0);
7772: }
7773: ++l;
7774: next = next->next;
7775: }
7776: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7777: }
7779: /*@C
7780: DMAddLabel - Add the label to this mesh
7782: Not Collective
7784: Input Parameters:
7785: + dm - The DM object
7786: - label - The DMLabel
7788: Level: developer
7790: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7791: @*/
7792: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7793: {
7794: DMLabelLink l, *p, tmpLabel;
7795: PetscBool hasLabel;
7796: const char *lname;
7797: PetscBool flg;
7802: PetscObjectGetName((PetscObject) label, &lname);
7803: DMHasLabel(dm, lname, &hasLabel);
7804: if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7805: PetscCalloc1(1, &tmpLabel);
7806: tmpLabel->label = label;
7807: tmpLabel->output = PETSC_TRUE;
7808: for (p=&dm->labels; (l=*p); p=&l->next) {}
7809: *p = tmpLabel;
7810: PetscObjectReference((PetscObject)label);
7811: PetscStrcmp(lname, "depth", &flg);
7812: if (flg) dm->depthLabel = label;
7813: PetscStrcmp(lname, "celltype", &flg);
7814: if (flg) dm->celltypeLabel = label;
7815: return(0);
7816: }
7818: /*@C
7819: DMRemoveLabel - Remove the label given by name from this mesh
7821: Not Collective
7823: Input Parameters:
7824: + dm - The DM object
7825: - name - The label name
7827: Output Parameter:
7828: . label - The DMLabel, or NULL if the label is absent
7830: Level: developer
7832: Notes:
7833: DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7834: DMLabelDestroy() on the label.
7836: DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7837: call DMLabelDestroy(). Instead, the label is returned and the user is
7838: responsible of calling DMLabelDestroy() at some point.
7840: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7841: @*/
7842: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7843: {
7844: DMLabelLink link, *pnext;
7845: PetscBool hasLabel;
7846: const char *lname;
7852: if (label) {
7854: *label = NULL;
7855: }
7856: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7857: PetscObjectGetName((PetscObject) link->label, &lname);
7858: PetscStrcmp(name, lname, &hasLabel);
7859: if (hasLabel) {
7860: *pnext = link->next; /* Remove from list */
7861: PetscStrcmp(name, "depth", &hasLabel);
7862: if (hasLabel) dm->depthLabel = NULL;
7863: PetscStrcmp(name, "celltype", &hasLabel);
7864: if (hasLabel) dm->celltypeLabel = NULL;
7865: if (label) *label = link->label;
7866: else {DMLabelDestroy(&link->label);}
7867: PetscFree(link);
7868: break;
7869: }
7870: }
7871: return(0);
7872: }
7874: /*@
7875: DMRemoveLabelBySelf - Remove the label from this mesh
7877: Not Collective
7879: Input Parameters:
7880: + dm - The DM object
7881: . label - (Optional) The DMLabel to be removed from the DM
7882: - failNotFound - Should it fail if the label is not found in the DM?
7884: Level: developer
7886: Notes:
7887: Only exactly the same instance is removed if found, name match is ignored.
7888: If the DM has an exclusive reference to the label, it gets destroyed and
7889: *label nullified.
7891: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7892: @*/
7893: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7894: {
7895: DMLabelLink link, *pnext;
7896: PetscBool hasLabel = PETSC_FALSE;
7902: if (!*label && !failNotFound) return(0);
7905: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7906: if (*label == link->label) {
7907: hasLabel = PETSC_TRUE;
7908: *pnext = link->next; /* Remove from list */
7909: if (*label == dm->depthLabel) dm->depthLabel = NULL;
7910: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7911: if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7912: DMLabelDestroy(&link->label);
7913: PetscFree(link);
7914: break;
7915: }
7916: }
7917: if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7918: return(0);
7919: }
7921: /*@C
7922: DMGetLabelOutput - Get the output flag for a given label
7924: Not Collective
7926: Input Parameters:
7927: + dm - The DM object
7928: - name - The label name
7930: Output Parameter:
7931: . output - The flag for output
7933: Level: developer
7935: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7936: @*/
7937: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7938: {
7939: DMLabelLink next = dm->labels;
7940: const char *lname;
7947: while (next) {
7948: PetscBool flg;
7950: PetscObjectGetName((PetscObject) next->label, &lname);
7951: PetscStrcmp(name, lname, &flg);
7952: if (flg) {*output = next->output; return(0);}
7953: next = next->next;
7954: }
7955: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7956: }
7958: /*@C
7959: DMSetLabelOutput - Set the output flag for a given label
7961: Not Collective
7963: Input Parameters:
7964: + dm - The DM object
7965: . name - The label name
7966: - output - The flag for output
7968: Level: developer
7970: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7971: @*/
7972: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7973: {
7974: DMLabelLink next = dm->labels;
7975: const char *lname;
7981: while (next) {
7982: PetscBool flg;
7984: PetscObjectGetName((PetscObject) next->label, &lname);
7985: PetscStrcmp(name, lname, &flg);
7986: if (flg) {next->output = output; return(0);}
7987: next = next->next;
7988: }
7989: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7990: }
7992: /*@
7993: DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7995: Collective on dmA
7997: Input Parameter:
7998: + dmA - The DM object with initial labels
7999: . dmB - The DM object with copied labels
8000: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8001: - all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8003: Level: intermediate
8005: Note: This is typically used when interpolating or otherwise adding to a mesh
8007: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8008: @*/
8009: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8010: {
8011: DMLabel label, labelNew;
8012: const char *name;
8013: PetscBool flg;
8014: DMLabelLink link;
8022: if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8023: if (dmA == dmB) return(0);
8024: for (link=dmA->labels; link; link=link->next) {
8025: label=link->label;
8026: PetscObjectGetName((PetscObject)label, &name);
8027: if (!all) {
8028: PetscStrcmp(name, "depth", &flg);
8029: if (flg) continue;
8030: PetscStrcmp(name, "dim", &flg);
8031: if (flg) continue;
8032: PetscStrcmp(name, "celltype", &flg);
8033: if (flg) continue;
8034: }
8035: if (mode==PETSC_COPY_VALUES) {
8036: DMLabelDuplicate(label, &labelNew);
8037: } else {
8038: labelNew = label;
8039: }
8040: DMAddLabel(dmB, labelNew);
8041: if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8042: }
8043: return(0);
8044: }
8046: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8047: {
8051: if (!*label) {
8052: DMCreateLabel(dm, name);
8053: DMGetLabel(dm, name, label);
8054: }
8055: DMLabelSetValue(*label, point, value);
8056: return(0);
8057: }
8059: /*
8060: Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8061: like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8062: (label, id) pair in the DM.
8064: However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8065: each label.
8066: */
8067: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8068: {
8069: DMUniversalLabel ul;
8070: PetscBool *active;
8071: PetscInt pStart, pEnd, p, Nl, l, m;
8072: PetscErrorCode ierr;
8075: PetscMalloc1(1, &ul);
8076: DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8077: DMGetNumLabels(dm, &Nl);
8078: PetscCalloc1(Nl, &active);
8079: ul->Nl = 0;
8080: for (l = 0; l < Nl; ++l) {
8081: PetscBool isdepth, iscelltype;
8082: const char *name;
8084: DMGetLabelName(dm, l, &name);
8085: PetscStrncmp(name, "depth", 6, &isdepth);
8086: PetscStrncmp(name, "celltype", 9, &iscelltype);
8087: active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8088: if (active[l]) ++ul->Nl;
8089: }
8090: PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8091: ul->Nv = 0;
8092: for (l = 0, m = 0; l < Nl; ++l) {
8093: DMLabel label;
8094: PetscInt nv;
8095: const char *name;
8097: if (!active[l]) continue;
8098: DMGetLabelName(dm, l, &name);
8099: DMGetLabelByNum(dm, l, &label);
8100: DMLabelGetNumValues(label, &nv);
8101: PetscStrallocpy(name, &ul->names[m]);
8102: ul->indices[m] = l;
8103: ul->Nv += nv;
8104: ul->offsets[m+1] = nv;
8105: ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1));
8106: ++m;
8107: }
8108: for (l = 1; l <= ul->Nl; ++l) {
8109: ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8110: ul->bits[l] = ul->bits[l-1] + ul->bits[l];
8111: }
8112: for (l = 0; l < ul->Nl; ++l) {
8113: PetscInt b;
8115: ul->masks[l] = 0;
8116: for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8117: }
8118: PetscMalloc1(ul->Nv, &ul->values);
8119: for (l = 0, m = 0; l < Nl; ++l) {
8120: DMLabel label;
8121: IS valueIS;
8122: const PetscInt *varr;
8123: PetscInt nv, v;
8125: if (!active[l]) continue;
8126: DMGetLabelByNum(dm, l, &label);
8127: DMLabelGetNumValues(label, &nv);
8128: DMLabelGetValueIS(label, &valueIS);
8129: ISGetIndices(valueIS, &varr);
8130: for (v = 0; v < nv; ++v) {
8131: ul->values[ul->offsets[m]+v] = varr[v];
8132: }
8133: ISRestoreIndices(valueIS, &varr);
8134: ISDestroy(&valueIS);
8135: PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8136: ++m;
8137: }
8138: DMPlexGetChart(dm, &pStart, &pEnd);
8139: for (p = pStart; p < pEnd; ++p) {
8140: PetscInt uval = 0;
8141: PetscBool marked = PETSC_FALSE;
8143: for (l = 0, m = 0; l < Nl; ++l) {
8144: DMLabel label;
8145: PetscInt val, defval, loc, nv;
8147: if (!active[l]) continue;
8148: DMGetLabelByNum(dm, l, &label);
8149: DMLabelGetValue(label, p, &val);
8150: DMLabelGetDefaultValue(label, &defval);
8151: if (val == defval) {++m; continue;}
8152: nv = ul->offsets[m+1]-ul->offsets[m];
8153: marked = PETSC_TRUE;
8154: PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8155: if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8156: uval += (loc+1) << ul->bits[m];
8157: ++m;
8158: }
8159: if (marked) {DMLabelSetValue(ul->label, p, uval);}
8160: }
8161: PetscFree(active);
8162: *universal = ul;
8163: return(0);
8164: }
8166: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8167: {
8168: PetscInt l;
8172: for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8173: DMLabelDestroy(&(*universal)->label);
8174: PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8175: PetscFree((*universal)->values);
8176: PetscFree(*universal);
8177: *universal = NULL;
8178: return(0);
8179: }
8181: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8182: {
8185: *ulabel = ul->label;
8186: return(0);
8187: }
8189: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8190: {
8191: PetscInt Nl = ul->Nl, l;
8196: for (l = 0; l < Nl; ++l) {
8197: if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8198: else {DMCreateLabel(dm, ul->names[l]);}
8199: }
8200: if (preserveOrder) {
8201: for (l = 0; l < ul->Nl; ++l) {
8202: const char *name;
8203: PetscBool match;
8205: DMGetLabelName(dm, ul->indices[l], &name);
8206: PetscStrcmp(name, ul->names[l], &match);
8207: if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8208: }
8209: }
8210: return(0);
8211: }
8213: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8214: {
8215: PetscInt l;
8219: for (l = 0; l < ul->Nl; ++l) {
8220: DMLabel label;
8221: PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8223: if (lval) {
8224: if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8225: else {DMGetLabel(dm, ul->names[l], &label);}
8226: DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8227: }
8228: }
8229: return(0);
8230: }
8232: /*@
8233: DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8235: Input Parameter:
8236: . dm - The DM object
8238: Output Parameter:
8239: . cdm - The coarse DM
8241: Level: intermediate
8243: .seealso: DMSetCoarseDM()
8244: @*/
8245: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8246: {
8250: *cdm = dm->coarseMesh;
8251: return(0);
8252: }
8254: /*@
8255: DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8257: Input Parameters:
8258: + dm - The DM object
8259: - cdm - The coarse DM
8261: Level: intermediate
8263: .seealso: DMGetCoarseDM()
8264: @*/
8265: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8266: {
8272: PetscObjectReference((PetscObject)cdm);
8273: DMDestroy(&dm->coarseMesh);
8274: dm->coarseMesh = cdm;
8275: return(0);
8276: }
8278: /*@
8279: DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8281: Input Parameter:
8282: . dm - The DM object
8284: Output Parameter:
8285: . fdm - The fine DM
8287: Level: intermediate
8289: .seealso: DMSetFineDM()
8290: @*/
8291: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8292: {
8296: *fdm = dm->fineMesh;
8297: return(0);
8298: }
8300: /*@
8301: DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8303: Input Parameters:
8304: + dm - The DM object
8305: - fdm - The fine DM
8307: Level: intermediate
8309: .seealso: DMGetFineDM()
8310: @*/
8311: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8312: {
8318: PetscObjectReference((PetscObject)fdm);
8319: DMDestroy(&dm->fineMesh);
8320: dm->fineMesh = fdm;
8321: return(0);
8322: }
8324: /*=== DMBoundary code ===*/
8326: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
8327: {
8328: PetscInt d;
8332: for (d = 0; d < dm->Nds; ++d) {
8333: PetscDSCopyBoundary(dm->probs[d].ds, PETSC_DETERMINE, NULL, dmNew->probs[d].ds);
8334: }
8335: return(0);
8336: }
8338: /*@C
8339: DMAddBoundary - Add a boundary condition to the model
8341: Collective on dm
8343: Input Parameters:
8344: + dm - The DM, with a PetscDS that matches the problem being constrained
8345: . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8346: . name - The BC name
8347: . labelname - The label defining constrained points
8348: . field - The field to constrain
8349: . numcomps - The number of constrained field components (0 will constrain all fields)
8350: . comps - An array of constrained component numbers
8351: . bcFunc - A pointwise function giving boundary values
8352: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8353: . numids - The number of DMLabel ids for constrained points
8354: . ids - An array of ids for constrained points
8355: - ctx - An optional user context for bcFunc
8357: Options Database Keys:
8358: + -bc_<boundary name> <num> - Overrides the boundary ids
8359: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8361: Note:
8362: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8364: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8366: If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8368: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8369: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8370: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8371: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
8373: + dim - the spatial dimension
8374: . Nf - the number of fields
8375: . uOff - the offset into u[] and u_t[] for each field
8376: . uOff_x - the offset into u_x[] for each field
8377: . u - each field evaluated at the current point
8378: . u_t - the time derivative of each field evaluated at the current point
8379: . u_x - the gradient of each field evaluated at the current point
8380: . aOff - the offset into a[] and a_t[] for each auxiliary field
8381: . aOff_x - the offset into a_x[] for each auxiliary field
8382: . a - each auxiliary field evaluated at the current point
8383: . a_t - the time derivative of each auxiliary field evaluated at the current point
8384: . a_x - the gradient of auxiliary each field evaluated at the current point
8385: . t - current time
8386: . x - coordinates of the current point
8387: . numConstants - number of constant parameters
8388: . constants - constant parameters
8389: - bcval - output values at the current point
8391: Level: developer
8393: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8394: @*/
8395: 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)
8396: {
8397: PetscDS ds;
8406: DMGetDS(dm, &ds);
8407: DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8408: PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8409: return(0);
8410: }
8412: /*@
8413: DMGetNumBoundary - Get the number of registered BC
8415: Input Parameters:
8416: . dm - The mesh object
8418: Output Parameters:
8419: . numBd - The number of BC
8421: Level: intermediate
8423: .seealso: DMAddBoundary(), DMGetBoundary()
8424: @*/
8425: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8426: {
8427: PetscDS ds;
8432: DMGetDS(dm, &ds);
8433: PetscDSGetNumBoundary(ds, numBd);
8434: return(0);
8435: }
8437: /*@C
8438: DMGetBoundary - Get a model boundary condition
8440: Input Parameters:
8441: + dm - The mesh object
8442: - bd - The BC number
8444: Output Parameters:
8445: + type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8446: . name - The BC name
8447: . labelname - The label defining constrained points
8448: . field - The field to constrain
8449: . numcomps - The number of constrained field components
8450: . comps - An array of constrained component numbers
8451: . bcFunc - A pointwise function giving boundary values
8452: . bcFunc_t - A pointwise function giving the time derviative of the boundary values
8453: . numids - The number of DMLabel ids for constrained points
8454: . ids - An array of ids for constrained points
8455: - ctx - An optional user context for bcFunc
8457: Options Database Keys:
8458: + -bc_<boundary name> <num> - Overrides the boundary ids
8459: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8461: Level: developer
8463: .seealso: DMAddBoundary()
8464: @*/
8465: 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)
8466: {
8467: PetscDS ds;
8472: DMGetDS(dm, &ds);
8473: PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8474: return(0);
8475: }
8477: static PetscErrorCode DMPopulateBoundary(DM dm)
8478: {
8479: PetscDS ds;
8480: DMBoundary *lastnext;
8481: DSBoundary dsbound;
8485: DMGetDS(dm, &ds);
8486: dsbound = ds->boundary;
8487: if (dm->boundary) {
8488: DMBoundary next = dm->boundary;
8490: /* quick check to see if the PetscDS has changed */
8491: if (next->dsboundary == dsbound) return(0);
8492: /* the PetscDS has changed: tear down and rebuild */
8493: while (next) {
8494: DMBoundary b = next;
8496: next = b->next;
8497: PetscFree(b);
8498: }
8499: dm->boundary = NULL;
8500: }
8502: lastnext = &(dm->boundary);
8503: while (dsbound) {
8504: DMBoundary dmbound;
8506: PetscNew(&dmbound);
8507: dmbound->dsboundary = dsbound;
8508: DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8509: if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8510: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8511: *lastnext = dmbound;
8512: lastnext = &(dmbound->next);
8513: dsbound = dsbound->next;
8514: }
8515: return(0);
8516: }
8518: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8519: {
8520: DMBoundary b;
8526: *isBd = PETSC_FALSE;
8527: DMPopulateBoundary(dm);
8528: b = dm->boundary;
8529: while (b && !(*isBd)) {
8530: DMLabel label = b->label;
8531: DSBoundary dsb = b->dsboundary;
8533: if (label) {
8534: PetscInt i;
8536: for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8537: DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8538: }
8539: }
8540: b = b->next;
8541: }
8542: return(0);
8543: }
8545: /*@C
8546: DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8548: Collective on DM
8550: Input Parameters:
8551: + dm - The DM
8552: . time - The time
8553: . funcs - The coordinate functions to evaluate, one per field
8554: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8555: - mode - The insertion mode for values
8557: Output Parameter:
8558: . X - vector
8560: Calling sequence of func:
8561: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8563: + dim - The spatial dimension
8564: . time - The time at which to sample
8565: . x - The coordinates
8566: . Nf - The number of fields
8567: . u - The output field values
8568: - ctx - optional user-defined function context
8570: Level: developer
8572: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8573: @*/
8574: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8575: {
8576: Vec localX;
8581: DMGetLocalVector(dm, &localX);
8582: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8583: DMLocalToGlobalBegin(dm, localX, mode, X);
8584: DMLocalToGlobalEnd(dm, localX, mode, X);
8585: DMRestoreLocalVector(dm, &localX);
8586: return(0);
8587: }
8589: /*@C
8590: DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8592: Not collective
8594: Input Parameters:
8595: + dm - The DM
8596: . time - The time
8597: . funcs - The coordinate functions to evaluate, one per field
8598: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8599: - mode - The insertion mode for values
8601: Output Parameter:
8602: . localX - vector
8604: Calling sequence of func:
8605: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8607: + dim - The spatial dimension
8608: . x - The coordinates
8609: . Nf - The number of fields
8610: . u - The output field values
8611: - ctx - optional user-defined function context
8613: Level: developer
8615: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8616: @*/
8617: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8618: {
8624: if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8625: (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8626: return(0);
8627: }
8629: /*@C
8630: 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.
8632: Collective on DM
8634: Input Parameters:
8635: + dm - The DM
8636: . time - The time
8637: . label - The DMLabel selecting the portion of the mesh for projection
8638: . funcs - The coordinate functions to evaluate, one per field
8639: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8640: - mode - The insertion mode for values
8642: Output Parameter:
8643: . X - vector
8645: Calling sequence of func:
8646: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8648: + dim - The spatial dimension
8649: . x - The coordinates
8650: . Nf - The number of fields
8651: . u - The output field values
8652: - ctx - optional user-defined function context
8654: Level: developer
8656: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8657: @*/
8658: 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)
8659: {
8660: Vec localX;
8665: DMGetLocalVector(dm, &localX);
8666: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8667: DMLocalToGlobalBegin(dm, localX, mode, X);
8668: DMLocalToGlobalEnd(dm, localX, mode, X);
8669: DMRestoreLocalVector(dm, &localX);
8670: return(0);
8671: }
8673: /*@C
8674: 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.
8676: Not collective
8678: Input Parameters:
8679: + dm - The DM
8680: . time - The time
8681: . label - The DMLabel selecting the portion of the mesh for projection
8682: . funcs - The coordinate functions to evaluate, one per field
8683: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8684: - mode - The insertion mode for values
8686: Output Parameter:
8687: . localX - vector
8689: Calling sequence of func:
8690: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8692: + dim - The spatial dimension
8693: . x - The coordinates
8694: . Nf - The number of fields
8695: . u - The output field values
8696: - ctx - optional user-defined function context
8698: Level: developer
8700: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8701: @*/
8702: 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)
8703: {
8709: if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8710: (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8711: return(0);
8712: }
8714: /*@C
8715: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8717: Not collective
8719: Input Parameters:
8720: + dm - The DM
8721: . time - The time
8722: . localU - The input field vector
8723: . funcs - The functions to evaluate, one per field
8724: - mode - The insertion mode for values
8726: Output Parameter:
8727: . localX - The output vector
8729: Calling sequence of func:
8730: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8731: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8732: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8733: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8735: + dim - The spatial dimension
8736: . Nf - The number of input fields
8737: . NfAux - The number of input auxiliary fields
8738: . uOff - The offset of each field in u[]
8739: . uOff_x - The offset of each field in u_x[]
8740: . u - The field values at this point in space
8741: . u_t - The field time derivative at this point in space (or NULL)
8742: . u_x - The field derivatives at this point in space
8743: . aOff - The offset of each auxiliary field in u[]
8744: . aOff_x - The offset of each auxiliary field in u_x[]
8745: . a - The auxiliary field values at this point in space
8746: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8747: . a_x - The auxiliary field derivatives at this point in space
8748: . t - The current time
8749: . x - The coordinates of this point
8750: . numConstants - The number of constants
8751: . constants - The value of each constant
8752: - f - The value of the function at this point in space
8754: 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.
8755: 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
8756: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8757: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8759: Level: intermediate
8761: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8762: @*/
8763: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8764: void (**funcs)(PetscInt, PetscInt, PetscInt,
8765: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8766: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8767: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8768: InsertMode mode, Vec localX)
8769: {
8776: if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8777: (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8778: return(0);
8779: }
8781: /*@C
8782: 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.
8784: Not collective
8786: Input Parameters:
8787: + dm - The DM
8788: . time - The time
8789: . label - The DMLabel marking the portion of the domain to output
8790: . numIds - The number of label ids to use
8791: . ids - The label ids to use for marking
8792: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8793: . comps - The components to set in the output, or NULL for all components
8794: . localU - The input field vector
8795: . funcs - The functions to evaluate, one per field
8796: - mode - The insertion mode for values
8798: Output Parameter:
8799: . localX - The output vector
8801: Calling sequence of func:
8802: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8803: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8804: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8805: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8807: + dim - The spatial dimension
8808: . Nf - The number of input fields
8809: . NfAux - The number of input auxiliary fields
8810: . uOff - The offset of each field in u[]
8811: . uOff_x - The offset of each field in u_x[]
8812: . u - The field values at this point in space
8813: . u_t - The field time derivative at this point in space (or NULL)
8814: . u_x - The field derivatives at this point in space
8815: . aOff - The offset of each auxiliary field in u[]
8816: . aOff_x - The offset of each auxiliary field in u_x[]
8817: . a - The auxiliary field values at this point in space
8818: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8819: . a_x - The auxiliary field derivatives at this point in space
8820: . t - The current time
8821: . x - The coordinates of this point
8822: . numConstants - The number of constants
8823: . constants - The value of each constant
8824: - f - The value of the function at this point in space
8826: 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.
8827: 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
8828: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8829: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8831: Level: intermediate
8833: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8834: @*/
8835: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8836: void (**funcs)(PetscInt, PetscInt, PetscInt,
8837: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8838: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8839: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8840: InsertMode mode, Vec localX)
8841: {
8848: if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8849: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8850: return(0);
8851: }
8853: /*@C
8854: 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.
8856: Not collective
8858: Input Parameters:
8859: + dm - The DM
8860: . time - The time
8861: . label - The DMLabel marking the portion of the domain boundary to output
8862: . numIds - The number of label ids to use
8863: . ids - The label ids to use for marking
8864: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8865: . comps - The components to set in the output, or NULL for all components
8866: . localU - The input field vector
8867: . funcs - The functions to evaluate, one per field
8868: - mode - The insertion mode for values
8870: Output Parameter:
8871: . localX - The output vector
8873: Calling sequence of func:
8874: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8875: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8876: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8877: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8879: + dim - The spatial dimension
8880: . Nf - The number of input fields
8881: . NfAux - The number of input auxiliary fields
8882: . uOff - The offset of each field in u[]
8883: . uOff_x - The offset of each field in u_x[]
8884: . u - The field values at this point in space
8885: . u_t - The field time derivative at this point in space (or NULL)
8886: . u_x - The field derivatives at this point in space
8887: . aOff - The offset of each auxiliary field in u[]
8888: . aOff_x - The offset of each auxiliary field in u_x[]
8889: . a - The auxiliary field values at this point in space
8890: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8891: . a_x - The auxiliary field derivatives at this point in space
8892: . t - The current time
8893: . x - The coordinates of this point
8894: . n - The face normal
8895: . numConstants - The number of constants
8896: . constants - The value of each constant
8897: - f - The value of the function at this point in space
8899: Note:
8900: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8901: 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
8902: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8903: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8905: Level: intermediate
8907: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8908: @*/
8909: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8910: void (**funcs)(PetscInt, PetscInt, PetscInt,
8911: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8912: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8913: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8914: InsertMode mode, Vec localX)
8915: {
8922: if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8923: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8924: return(0);
8925: }
8927: /*@C
8928: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8930: Input Parameters:
8931: + dm - The DM
8932: . time - The time
8933: . funcs - The functions to evaluate for each field component
8934: . ctxs - Optional array of contexts to pass to each function, or NULL.
8935: - X - The coefficient vector u_h, a global vector
8937: Output Parameter:
8938: . diff - The diff ||u - u_h||_2
8940: Level: developer
8942: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8943: @*/
8944: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8945: {
8951: if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8952: (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8953: return(0);
8954: }
8956: /*@C
8957: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8959: Collective on dm
8961: Input Parameters:
8962: + dm - The DM
8963: , time - The time
8964: . funcs - The gradient functions to evaluate for each field component
8965: . ctxs - Optional array of contexts to pass to each function, or NULL.
8966: . X - The coefficient vector u_h, a global vector
8967: - n - The vector to project along
8969: Output Parameter:
8970: . diff - The diff ||(grad u - grad u_h) . n||_2
8972: Level: developer
8974: .seealso: DMProjectFunction(), DMComputeL2Diff()
8975: @*/
8976: 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)
8977: {
8983: if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8984: (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8985: return(0);
8986: }
8988: /*@C
8989: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8991: Collective on dm
8993: Input Parameters:
8994: + dm - The DM
8995: . time - The time
8996: . funcs - The functions to evaluate for each field component
8997: . ctxs - Optional array of contexts to pass to each function, or NULL.
8998: - X - The coefficient vector u_h, a global vector
9000: Output Parameter:
9001: . diff - The array of differences, ||u^f - u^f_h||_2
9003: Level: developer
9005: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9006: @*/
9007: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9008: {
9014: if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9015: (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9016: return(0);
9017: }
9019: /*@C
9020: DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags. Specific implementations of DM maybe have
9021: specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
9023: Collective on dm
9025: Input parameters:
9026: + dm - the pre-adaptation DM object
9027: - label - label with the flags
9029: Output parameters:
9030: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
9032: Level: intermediate
9034: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9035: @*/
9036: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9037: {
9044: *dmAdapt = NULL;
9045: if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9046: (dm->ops->adaptlabel)(dm, label, dmAdapt);
9047: if (*dmAdapt) {
9048: (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
9049: PetscFree((*dmAdapt)->vectype);
9050: PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9051: PetscFree((*dmAdapt)->mattype);
9052: PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9053: }
9054: return(0);
9055: }
9057: /*@C
9058: DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
9060: Input Parameters:
9061: + dm - The DM object
9062: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9063: - 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_".
9065: Output Parameter:
9066: . dmAdapt - Pointer to the DM object containing the adapted mesh
9068: Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
9070: Level: advanced
9072: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9073: @*/
9074: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9075: {
9083: *dmAdapt = NULL;
9084: if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9085: (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9086: return(0);
9087: }
9089: /*@C
9090: DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9092: Not Collective
9094: Input Parameter:
9095: . dm - The DM
9097: Output Parameters:
9098: + nranks - the number of neighbours
9099: - ranks - the neighbors ranks
9101: Notes:
9102: Do not free the array, it is freed when the DM is destroyed.
9104: Level: beginner
9106: .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9107: @*/
9108: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9109: {
9114: if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9115: (dm->ops->getneighbors)(dm,nranks,ranks);
9116: return(0);
9117: }
9119: #include <petsc/private/matimpl.h>
9121: /*
9122: Converts the input vector to a ghosted vector and then calls the standard coloring code.
9123: This has be a different function because it requires DM which is not defined in the Mat library
9124: */
9125: PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9126: {
9130: if (coloring->ctype == IS_COLORING_LOCAL) {
9131: Vec x1local;
9132: DM dm;
9133: MatGetDM(J,&dm);
9134: if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9135: DMGetLocalVector(dm,&x1local);
9136: DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9137: DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9138: x1 = x1local;
9139: }
9140: MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9141: if (coloring->ctype == IS_COLORING_LOCAL) {
9142: DM dm;
9143: MatGetDM(J,&dm);
9144: DMRestoreLocalVector(dm,&x1);
9145: }
9146: return(0);
9147: }
9149: /*@
9150: MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9152: Input Parameter:
9153: . coloring - the MatFDColoring object
9155: Developer Notes:
9156: this routine exists because the PETSc Mat library does not know about the DM objects
9158: Level: advanced
9160: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9161: @*/
9162: PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9163: {
9165: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9166: return(0);
9167: }
9169: /*@
9170: DMGetCompatibility - determine if two DMs are compatible
9172: Collective
9174: Input Parameters:
9175: + dm1 - the first DM
9176: - dm2 - the second DM
9178: Output Parameters:
9179: + compatible - whether or not the two DMs are compatible
9180: - set - whether or not the compatible value was set
9182: Notes:
9183: Two DMs are deemed compatible if they represent the same parallel decomposition
9184: of the same topology. This implies that the section (field data) on one
9185: "makes sense" with respect to the topology and parallel decomposition of the other.
9186: Loosely speaking, compatible DMs represent the same domain and parallel
9187: decomposition, but hold different data.
9189: Typically, one would confirm compatibility if intending to simultaneously iterate
9190: over a pair of vectors obtained from different DMs.
9192: For example, two DMDA objects are compatible if they have the same local
9193: and global sizes and the same stencil width. They can have different numbers
9194: of degrees of freedom per node. Thus, one could use the node numbering from
9195: either DM in bounds for a loop over vectors derived from either DM.
9197: Consider the operation of summing data living on a 2-dof DMDA to data living
9198: on a 1-dof DMDA, which should be compatible, as in the following snippet.
9199: .vb
9200: ...
9201: DMGetCompatibility(da1,da2,&compatible,&set);
9202: if (set && compatible) {
9203: DMDAVecGetArrayDOF(da1,vec1,&arr1);
9204: DMDAVecGetArrayDOF(da2,vec2,&arr2);
9205: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9206: for (j=y; j<y+n; ++j) {
9207: for (i=x; i<x+m, ++i) {
9208: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9209: }
9210: }
9211: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9212: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9213: } else {
9214: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9215: }
9216: ...
9217: .ve
9219: Checking compatibility might be expensive for a given implementation of DM,
9220: or might be impossible to unambiguously confirm or deny. For this reason,
9221: this function may decline to determine compatibility, and hence users should
9222: always check the "set" output parameter.
9224: A DM is always compatible with itself.
9226: In the current implementation, DMs which live on "unequal" communicators
9227: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9228: incompatible.
9230: This function is labeled "Collective," as information about all subdomains
9231: is required on each rank. However, in DM implementations which store all this
9232: information locally, this function may be merely "Logically Collective".
9234: Developer Notes:
9235: Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9236: iff B is compatible with A. Thus, this function checks the implementations
9237: of both dm and dmc (if they are of different types), attempting to determine
9238: compatibility. It is left to DM implementers to ensure that symmetry is
9239: preserved. The simplest way to do this is, when implementing type-specific
9240: logic for this function, is to check for existing logic in the implementation
9241: of other DM types and let *set = PETSC_FALSE if found.
9243: Level: advanced
9245: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9246: @*/
9248: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9249: {
9251: PetscMPIInt compareResult;
9252: DMType type,type2;
9253: PetscBool sameType;
9259: /* Declare a DM compatible with itself */
9260: if (dm1 == dm2) {
9261: *set = PETSC_TRUE;
9262: *compatible = PETSC_TRUE;
9263: return(0);
9264: }
9266: /* Declare a DM incompatible with a DM that lives on an "unequal"
9267: communicator. Note that this does not preclude compatibility with
9268: DMs living on "congruent" or "similar" communicators, but this must be
9269: determined by the implementation-specific logic */
9270: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9271: if (compareResult == MPI_UNEQUAL) {
9272: *set = PETSC_TRUE;
9273: *compatible = PETSC_FALSE;
9274: return(0);
9275: }
9277: /* Pass to the implementation-specific routine, if one exists. */
9278: if (dm1->ops->getcompatibility) {
9279: (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9280: if (*set) return(0);
9281: }
9283: /* If dm1 and dm2 are of different types, then attempt to check compatibility
9284: with an implementation of this function from dm2 */
9285: DMGetType(dm1,&type);
9286: DMGetType(dm2,&type2);
9287: PetscStrcmp(type,type2,&sameType);
9288: if (!sameType && dm2->ops->getcompatibility) {
9289: (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9290: } else {
9291: *set = PETSC_FALSE;
9292: }
9293: return(0);
9294: }
9296: /*@C
9297: DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9299: Logically Collective on DM
9301: Input Parameters:
9302: + DM - the DM
9303: . f - the monitor function
9304: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9305: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9307: Options Database Keys:
9308: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9309: does not cancel those set via the options database.
9311: Notes:
9312: Several different monitoring routines may be set by calling
9313: DMMonitorSet() multiple times; all will be called in the
9314: order in which they were set.
9316: Fortran Notes:
9317: Only a single monitor function can be set for each DM object
9319: Level: intermediate
9321: .seealso: DMMonitorCancel()
9322: @*/
9323: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9324: {
9325: PetscInt m;
9330: for (m = 0; m < dm->numbermonitors; ++m) {
9331: PetscBool identical;
9333: PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9334: if (identical) return(0);
9335: }
9336: if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9337: dm->monitor[dm->numbermonitors] = f;
9338: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
9339: dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9340: return(0);
9341: }
9343: /*@
9344: DMMonitorCancel - Clears all the monitor functions for a DM object.
9346: Logically Collective on DM
9348: Input Parameter:
9349: . dm - the DM
9351: Options Database Key:
9352: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9353: into a code by calls to DMonitorSet(), but does not cancel those
9354: set via the options database
9356: Notes:
9357: There is no way to clear one specific monitor from a DM object.
9359: Level: intermediate
9361: .seealso: DMMonitorSet()
9362: @*/
9363: PetscErrorCode DMMonitorCancel(DM dm)
9364: {
9366: PetscInt m;
9370: for (m = 0; m < dm->numbermonitors; ++m) {
9371: if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9372: }
9373: dm->numbermonitors = 0;
9374: return(0);
9375: }
9377: /*@C
9378: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9380: Collective on DM
9382: Input Parameters:
9383: + dm - DM object you wish to monitor
9384: . name - the monitor type one is seeking
9385: . help - message indicating what monitoring is done
9386: . manual - manual page for the monitor
9387: . monitor - the monitor function
9388: - 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
9390: Output Parameter:
9391: . flg - Flag set if the monitor was created
9393: Level: developer
9395: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9396: PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9397: PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9398: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9399: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9400: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9401: PetscOptionsFList(), PetscOptionsEList()
9402: @*/
9403: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9404: {
9405: PetscViewer viewer;
9406: PetscViewerFormat format;
9407: PetscErrorCode ierr;
9411: PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9412: if (*flg) {
9413: PetscViewerAndFormat *vf;
9415: PetscViewerAndFormatCreate(viewer, format, &vf);
9416: PetscObjectDereference((PetscObject) viewer);
9417: if (monitorsetup) {(*monitorsetup)(dm, vf);}
9418: DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9419: }
9420: return(0);
9421: }
9423: /*@
9424: DMMonitor - runs the user provided monitor routines, if they exist
9426: Collective on DM
9428: Input Parameters:
9429: . dm - The DM
9431: Level: developer
9433: .seealso: DMMonitorSet()
9434: @*/
9435: PetscErrorCode DMMonitor(DM dm)
9436: {
9437: PetscInt m;
9441: if (!dm) return(0);
9443: for (m = 0; m < dm->numbermonitors; ++m) {
9444: (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9445: }
9446: return(0);
9447: }
9449: /*@
9450: DMComputeError - Computes the error assuming the user has given exact solution functions
9452: Collective on DM
9454: Input Parameters:
9455: + dm - The DM
9456: . sol - The solution vector
9457: . errors - An array of length Nf, the number of fields, or NULL for no output
9458: - errorVec - A Vec pointer, or NULL for no output
9460: Output Parameters:
9461: + errors - The error in each field
9462: - errorVec - Creates a vector to hold the cellwise error
9464: Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9466: Level: developer
9468: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9469: @*/
9470: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9471: {
9472: PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9473: void **ctxs;
9474: PetscReal time;
9475: PetscInt Nf, f, Nds, s;
9476: PetscErrorCode ierr;
9479: DMGetNumFields(dm, &Nf);
9480: PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9481: DMGetNumDS(dm, &Nds);
9482: for (s = 0; s < Nds; ++s) {
9483: PetscDS ds;
9484: DMLabel label;
9485: IS fieldIS;
9486: const PetscInt *fields;
9487: PetscInt dsNf;
9489: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9490: PetscDSGetNumFields(ds, &dsNf);
9491: if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9492: for (f = 0; f < dsNf; ++f) {
9493: const PetscInt field = fields[f];
9494: PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9495: }
9496: if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9497: }
9498: for (f = 0; f < Nf; ++f) {
9499: if (!exactSol[f]) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %D", f);
9500: }
9501: DMGetOutputSequenceNumber(dm, NULL, &time);
9502: if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9503: if (errorVec) {
9504: DM edm;
9505: DMPolytopeType ct;
9506: PetscBool simplex;
9507: PetscInt dim, cStart, Nf;
9509: DMClone(dm, &edm);
9510: DMGetDimension(edm, &dim);
9511: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9512: DMPlexGetCellType(dm, cStart, &ct);
9513: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9514: DMGetNumFields(dm, &Nf);
9515: for (f = 0; f < Nf; ++f) {
9516: PetscFE fe, efe;
9517: PetscQuadrature q;
9518: const char *name;
9520: DMGetField(dm, f, NULL, (PetscObject *) &fe);
9521: PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9522: PetscObjectGetName((PetscObject) fe, &name);
9523: PetscObjectSetName((PetscObject) efe, name);
9524: PetscFEGetQuadrature(fe, &q);
9525: PetscFESetQuadrature(efe, q);
9526: DMSetField(edm, f, NULL, (PetscObject) efe);
9527: PetscFEDestroy(&efe);
9528: }
9529: DMCreateDS(edm);
9531: DMCreateGlobalVector(edm, errorVec);
9532: PetscObjectSetName((PetscObject) *errorVec, "Error");
9533: DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9534: DMDestroy(&edm);
9535: }
9536: PetscFree2(exactSol, ctxs);
9537: return(0);
9538: }