Actual source code: dm.c
petsc-3.15.0 2021-03-30
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","INVALID","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
1336: Notes:
1337: This properly preallocates the number of nonzeros in the sparse matrix so you
1338: do not need to do it yourself.
1340: By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1341: the nonzero pattern call DMSetMatrixPreallocateOnly()
1343: For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1344: internally by PETSc.
1346: For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1347: the indices for the global numbering for DMDAs which is complicated.
1349: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1351: @*/
1352: PetscErrorCode DMCreateMatrix(DM dm,Mat *mat)
1353: {
1359: if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1360: MatInitializePackage();
1361: PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1362: (*dm->ops->creatematrix)(dm,mat);
1363: if (PetscDefined(USE_DEBUG)) {
1364: DM mdm;
1366: MatGetDM(*mat,&mdm);
1367: 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);
1368: }
1369: /* Handle nullspace and near nullspace */
1370: if (dm->Nf) {
1371: MatNullSpace nullSpace;
1372: PetscInt Nf, f;
1374: DMGetNumFields(dm, &Nf);
1375: for (f = 0; f < Nf; ++f) {
1376: if (dm->nullspaceConstructors[f]) {
1377: (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1378: MatSetNullSpace(*mat, nullSpace);
1379: MatNullSpaceDestroy(&nullSpace);
1380: break;
1381: }
1382: }
1383: for (f = 0; f < Nf; ++f) {
1384: if (dm->nearnullspaceConstructors[f]) {
1385: (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1386: MatSetNearNullSpace(*mat, nullSpace);
1387: MatNullSpaceDestroy(&nullSpace);
1388: }
1389: }
1390: }
1391: PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1392: return(0);
1393: }
1395: /*@
1396: DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1397: preallocated but the nonzero structure and zero values will not be set.
1399: Logically Collective on dm
1401: Input Parameter:
1402: + dm - the DM
1403: - only - PETSC_TRUE if only want preallocation
1405: Level: developer
1406: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1407: @*/
1408: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1409: {
1412: dm->prealloc_only = only;
1413: return(0);
1414: }
1416: /*@
1417: DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1418: but the array for values will not be allocated.
1420: Logically Collective on dm
1422: Input Parameter:
1423: + dm - the DM
1424: - only - PETSC_TRUE if only want matrix stucture
1426: Level: developer
1427: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1428: @*/
1429: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1430: {
1433: dm->structure_only = only;
1434: return(0);
1435: }
1437: /*@C
1438: DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1440: Not Collective
1442: Input Parameters:
1443: + dm - the DM object
1444: . count - The minium size
1445: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)
1447: Output Parameter:
1448: . array - the work array
1450: Level: developer
1452: .seealso DMDestroy(), DMCreate()
1453: @*/
1454: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1455: {
1457: DMWorkLink link;
1458: PetscMPIInt dsize;
1463: if (dm->workin) {
1464: link = dm->workin;
1465: dm->workin = dm->workin->next;
1466: } else {
1467: PetscNewLog(dm,&link);
1468: }
1469: MPI_Type_size(dtype,&dsize);
1470: if (((size_t)dsize*count) > link->bytes) {
1471: PetscFree(link->mem);
1472: PetscMalloc(dsize*count,&link->mem);
1473: link->bytes = dsize*count;
1474: }
1475: link->next = dm->workout;
1476: dm->workout = link;
1477: #if defined(PETSC_HAVE_VALGRIND)
1478: VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1479: VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1480: #endif
1481: *(void**)mem = link->mem;
1482: return(0);
1483: }
1485: /*@C
1486: DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1488: Not Collective
1490: Input Parameters:
1491: + dm - the DM object
1492: . count - The minium size
1493: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT
1495: Output Parameter:
1496: . array - the work array
1498: Level: developer
1500: Developer Notes:
1501: count and dtype are ignored, they are only needed for DMGetWorkArray()
1502: .seealso DMDestroy(), DMCreate()
1503: @*/
1504: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1505: {
1506: DMWorkLink *p,link;
1511: for (p=&dm->workout; (link=*p); p=&link->next) {
1512: if (link->mem == *(void**)mem) {
1513: *p = link->next;
1514: link->next = dm->workin;
1515: dm->workin = link;
1516: *(void**)mem = NULL;
1517: return(0);
1518: }
1519: }
1520: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1521: }
1523: /*@C
1524: DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field
1526: Logically collective on DM
1528: Input Parameters:
1529: + dm - The DM
1530: . field - The field number for the nullspace
1531: - nullsp - A callback to create the nullspace
1533: Notes:
1534: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1535: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1536: $ dm - The present DM
1537: $ origField - The field number given above, in the original DM
1538: $ field - The field number in dm
1539: $ nullSpace - The nullspace for the given field
1541: This function is currently not available from Fortran.
1543: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1544: */
1545: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1546: {
1549: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1550: dm->nullspaceConstructors[field] = nullsp;
1551: return(0);
1552: }
1554: /*@C
1555: DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL
1557: Not collective
1559: Input Parameters:
1560: + dm - The DM
1561: - field - The field number for the nullspace
1563: Output Parameter:
1564: . nullsp - A callback to create the nullspace
1566: Notes:
1567: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1568: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1569: $ dm - The present DM
1570: $ origField - The field number given above, in the original DM
1571: $ field - The field number in dm
1572: $ nullSpace - The nullspace for the given field
1574: This function is currently not available from Fortran.
1576: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1577: */
1578: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1579: {
1583: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1584: *nullsp = dm->nullspaceConstructors[field];
1585: return(0);
1586: }
1588: /*@C
1589: DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field
1591: Logically collective on DM
1593: Input Parameters:
1594: + dm - The DM
1595: . field - The field number for the nullspace
1596: - nullsp - A callback to create the near-nullspace
1598: Notes:
1599: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1600: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1601: $ dm - The present DM
1602: $ origField - The field number given above, in the original DM
1603: $ field - The field number in dm
1604: $ nullSpace - The nullspace for the given field
1606: This function is currently not available from Fortran.
1608: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1609: */
1610: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1611: {
1614: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1615: dm->nearnullspaceConstructors[field] = nullsp;
1616: return(0);
1617: }
1619: /*@C
1620: DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL
1622: Not collective
1624: Input Parameters:
1625: + dm - The DM
1626: - field - The field number for the nullspace
1628: Output Parameter:
1629: . nullsp - A callback to create the near-nullspace
1631: Notes:
1632: The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1633: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1634: $ dm - The present DM
1635: $ origField - The field number given above, in the original DM
1636: $ field - The field number in dm
1637: $ nullSpace - The nullspace for the given field
1639: This function is currently not available from Fortran.
1641: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1642: */
1643: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1644: {
1648: if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1649: *nullsp = dm->nearnullspaceConstructors[field];
1650: return(0);
1651: }
1653: /*@C
1654: DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1656: Not collective
1658: Input Parameter:
1659: . dm - the DM object
1661: Output Parameters:
1662: + numFields - The number of fields (or NULL if not requested)
1663: . fieldNames - The name for each field (or NULL if not requested)
1664: - fields - The global indices for each field (or NULL if not requested)
1666: Level: intermediate
1668: Notes:
1669: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1670: PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1671: PetscFree().
1673: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1674: @*/
1675: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1676: {
1677: PetscSection section, sectionGlobal;
1682: if (numFields) {
1684: *numFields = 0;
1685: }
1686: if (fieldNames) {
1688: *fieldNames = NULL;
1689: }
1690: if (fields) {
1692: *fields = NULL;
1693: }
1694: DMGetLocalSection(dm, §ion);
1695: if (section) {
1696: PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1697: PetscInt nF, f, pStart, pEnd, p;
1699: DMGetGlobalSection(dm, §ionGlobal);
1700: PetscSectionGetNumFields(section, &nF);
1701: PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1702: PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1703: for (f = 0; f < nF; ++f) {
1704: fieldSizes[f] = 0;
1705: PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1706: }
1707: for (p = pStart; p < pEnd; ++p) {
1708: PetscInt gdof;
1710: PetscSectionGetDof(sectionGlobal, p, &gdof);
1711: if (gdof > 0) {
1712: for (f = 0; f < nF; ++f) {
1713: PetscInt fdof, fcdof, fpdof;
1715: PetscSectionGetFieldDof(section, p, f, &fdof);
1716: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1717: fpdof = fdof-fcdof;
1718: if (fpdof && fpdof != fieldNc[f]) {
1719: /* Layout does not admit a pointwise block size */
1720: fieldNc[f] = 1;
1721: }
1722: fieldSizes[f] += fpdof;
1723: }
1724: }
1725: }
1726: for (f = 0; f < nF; ++f) {
1727: PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1728: fieldSizes[f] = 0;
1729: }
1730: for (p = pStart; p < pEnd; ++p) {
1731: PetscInt gdof, goff;
1733: PetscSectionGetDof(sectionGlobal, p, &gdof);
1734: if (gdof > 0) {
1735: PetscSectionGetOffset(sectionGlobal, p, &goff);
1736: for (f = 0; f < nF; ++f) {
1737: PetscInt fdof, fcdof, fc;
1739: PetscSectionGetFieldDof(section, p, f, &fdof);
1740: PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1741: for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1742: fieldIndices[f][fieldSizes[f]] = goff++;
1743: }
1744: }
1745: }
1746: }
1747: if (numFields) *numFields = nF;
1748: if (fieldNames) {
1749: PetscMalloc1(nF, fieldNames);
1750: for (f = 0; f < nF; ++f) {
1751: const char *fieldName;
1753: PetscSectionGetFieldName(section, f, &fieldName);
1754: PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1755: }
1756: }
1757: if (fields) {
1758: PetscMalloc1(nF, fields);
1759: for (f = 0; f < nF; ++f) {
1760: PetscInt bs, in[2], out[2];
1762: ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1763: in[0] = -fieldNc[f];
1764: in[1] = fieldNc[f];
1765: MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1766: bs = (-out[0] == out[1]) ? out[1] : 1;
1767: ISSetBlockSize((*fields)[f], bs);
1768: }
1769: }
1770: PetscFree3(fieldSizes,fieldNc,fieldIndices);
1771: } else if (dm->ops->createfieldis) {
1772: (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1773: }
1774: return(0);
1775: }
1778: /*@C
1779: DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1780: corresponding to different fields: each IS contains the global indices of the dofs of the
1781: corresponding field. The optional list of DMs define the DM for each subproblem.
1782: Generalizes DMCreateFieldIS().
1784: Not collective
1786: Input Parameter:
1787: . dm - the DM object
1789: Output Parameters:
1790: + len - The number of subproblems in the field decomposition (or NULL if not requested)
1791: . namelist - The name for each field (or NULL if not requested)
1792: . islist - The global indices for each field (or NULL if not requested)
1793: - dmlist - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1795: Level: intermediate
1797: Notes:
1798: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1799: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1800: and all of the arrays should be freed with PetscFree().
1802: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1803: @*/
1804: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1805: {
1810: if (len) {
1812: *len = 0;
1813: }
1814: if (namelist) {
1816: *namelist = NULL;
1817: }
1818: if (islist) {
1820: *islist = NULL;
1821: }
1822: if (dmlist) {
1824: *dmlist = NULL;
1825: }
1826: /*
1827: Is it a good idea to apply the following check across all impls?
1828: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1829: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1830: */
1831: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1832: if (!dm->ops->createfielddecomposition) {
1833: PetscSection section;
1834: PetscInt numFields, f;
1836: DMGetLocalSection(dm, §ion);
1837: if (section) {PetscSectionGetNumFields(section, &numFields);}
1838: if (section && numFields && dm->ops->createsubdm) {
1839: if (len) *len = numFields;
1840: if (namelist) {PetscMalloc1(numFields,namelist);}
1841: if (islist) {PetscMalloc1(numFields,islist);}
1842: if (dmlist) {PetscMalloc1(numFields,dmlist);}
1843: for (f = 0; f < numFields; ++f) {
1844: const char *fieldName;
1846: DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1847: if (namelist) {
1848: PetscSectionGetFieldName(section, f, &fieldName);
1849: PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1850: }
1851: }
1852: } else {
1853: DMCreateFieldIS(dm, len, namelist, islist);
1854: /* By default there are no DMs associated with subproblems. */
1855: if (dmlist) *dmlist = NULL;
1856: }
1857: } else {
1858: (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1859: }
1860: return(0);
1861: }
1863: /*@
1864: DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1865: The fields are defined by DMCreateFieldIS().
1867: Not collective
1869: Input Parameters:
1870: + dm - The DM object
1871: . numFields - The number of fields in this subproblem
1872: - fields - The field numbers of the selected fields
1874: Output Parameters:
1875: + is - The global indices for the subproblem
1876: - subdm - The DM for the subproblem
1878: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1880: Level: intermediate
1882: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1883: @*/
1884: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1885: {
1893: if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
1894: (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1895: return(0);
1896: }
1898: /*@C
1899: DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.
1901: Not collective
1903: Input Parameter:
1904: + dms - The DM objects
1905: - len - The number of DMs
1907: Output Parameters:
1908: + is - The global indices for the subproblem, or NULL
1909: - superdm - The DM for the superproblem
1911: Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed
1913: Level: intermediate
1915: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1916: @*/
1917: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1918: {
1919: PetscInt i;
1927: if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1928: if (len) {
1929: DM dm = dms[0];
1930: if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1931: (*dm->ops->createsuperdm)(dms, len, is, superdm);
1932: }
1933: return(0);
1934: }
1937: /*@C
1938: DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1939: corresponding to restrictions to pairs nested subdomains: each IS contains the global
1940: indices of the dofs of the corresponding subdomains. The inner subdomains conceptually
1941: define a nonoverlapping covering, while outer subdomains can overlap.
1942: The optional list of DMs define the DM for each subproblem.
1944: Not collective
1946: Input Parameter:
1947: . dm - the DM object
1949: Output Parameters:
1950: + len - The number of subproblems in the domain decomposition (or NULL if not requested)
1951: . namelist - The name for each subdomain (or NULL if not requested)
1952: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1953: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1954: - dmlist - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1956: Level: intermediate
1958: Notes:
1959: The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1960: PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1961: and all of the arrays should be freed with PetscFree().
1963: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1964: @*/
1965: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1966: {
1967: PetscErrorCode ierr;
1968: DMSubDomainHookLink link;
1969: PetscInt i,l;
1978: /*
1979: Is it a good idea to apply the following check across all impls?
1980: Perhaps some impls can have a well-defined decomposition before DMSetUp?
1981: This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1982: */
1983: if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1984: if (dm->ops->createdomaindecomposition) {
1985: (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1986: /* copy subdomain hooks and context over to the subdomain DMs */
1987: if (dmlist && *dmlist) {
1988: for (i = 0; i < l; i++) {
1989: for (link=dm->subdomainhook; link; link=link->next) {
1990: if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1991: }
1992: if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1993: }
1994: }
1995: if (len) *len = l;
1996: }
1997: return(0);
1998: }
2001: /*@C
2002: DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
2004: Not collective
2006: Input Parameters:
2007: + dm - the DM object
2008: . n - the number of subdomain scatters
2009: - subdms - the local subdomains
2011: Output Parameters:
2012: + n - the number of scatters returned
2013: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2014: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2015: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2017: Notes:
2018: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2019: of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2020: of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2021: solution and residual data.
2023: Level: developer
2025: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2026: @*/
2027: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2028: {
2034: if (!dm->ops->createddscatters) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateDomainDecompositionScatters",((PetscObject)dm)->type_name);
2035: (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2036: return(0);
2037: }
2039: /*@
2040: DMRefine - Refines a DM object
2042: Collective on dm
2044: Input Parameter:
2045: + dm - the DM object
2046: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2048: Output Parameter:
2049: . dmf - the refined DM, or NULL
2051: Options Dtabase Keys:
2052: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2054: Note: If no refinement was done, the return value is NULL
2056: Level: developer
2058: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2059: @*/
2060: PetscErrorCode DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2061: {
2062: PetscErrorCode ierr;
2063: DMRefineHookLink link;
2067: if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2068: PetscLogEventBegin(DM_Refine,dm,0,0,0);
2069: (*dm->ops->refine)(dm,comm,dmf);
2070: if (*dmf) {
2071: (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2073: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);
2075: (*dmf)->ctx = dm->ctx;
2076: (*dmf)->leveldown = dm->leveldown;
2077: (*dmf)->levelup = dm->levelup + 1;
2079: DMSetMatType(*dmf,dm->mattype);
2080: for (link=dm->refinehook; link; link=link->next) {
2081: if (link->refinehook) {
2082: (*link->refinehook)(dm,*dmf,link->ctx);
2083: }
2084: }
2085: }
2086: PetscLogEventEnd(DM_Refine,dm,0,0,0);
2087: return(0);
2088: }
2090: /*@C
2091: DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2093: Logically Collective
2095: Input Arguments:
2096: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2097: . refinehook - function to run when setting up a coarser level
2098: . interphook - function to run to update data on finer levels (once per SNESSolve())
2099: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2101: Calling sequence of refinehook:
2102: $ refinehook(DM coarse,DM fine,void *ctx);
2104: + coarse - coarse level DM
2105: . fine - fine level DM to interpolate problem to
2106: - ctx - optional user-defined function context
2108: Calling sequence for interphook:
2109: $ interphook(DM coarse,Mat interp,DM fine,void *ctx)
2111: + coarse - coarse level DM
2112: . interp - matrix interpolating a coarse-level solution to the finer grid
2113: . fine - fine level DM to update
2114: - ctx - optional user-defined function context
2116: Level: advanced
2118: Notes:
2119: This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
2121: If this function is called multiple times, the hooks will be run in the order they are added.
2123: This function is currently not available from Fortran.
2125: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2126: @*/
2127: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2128: {
2129: PetscErrorCode ierr;
2130: DMRefineHookLink link,*p;
2134: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2135: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2136: }
2137: PetscNew(&link);
2138: link->refinehook = refinehook;
2139: link->interphook = interphook;
2140: link->ctx = ctx;
2141: link->next = NULL;
2142: *p = link;
2143: return(0);
2144: }
2146: /*@C
2147: DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid
2149: Logically Collective
2151: Input Arguments:
2152: + coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2153: . refinehook - function to run when setting up a coarser level
2154: . interphook - function to run to update data on finer levels (once per SNESSolve())
2155: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2157: Level: advanced
2159: Notes:
2160: This function does nothing if the hook is not in the list.
2162: This function is currently not available from Fortran.
2164: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2165: @*/
2166: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2167: {
2168: PetscErrorCode ierr;
2169: DMRefineHookLink link,*p;
2173: for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2174: if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2175: link = *p;
2176: *p = link->next;
2177: PetscFree(link);
2178: break;
2179: }
2180: }
2181: return(0);
2182: }
2184: /*@
2185: DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
2187: Collective if any hooks are
2189: Input Arguments:
2190: + coarse - coarser DM to use as a base
2191: . interp - interpolation matrix, apply using MatInterpolate()
2192: - fine - finer DM to update
2194: Level: developer
2196: .seealso: DMRefineHookAdd(), MatInterpolate()
2197: @*/
2198: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2199: {
2200: PetscErrorCode ierr;
2201: DMRefineHookLink link;
2204: for (link=fine->refinehook; link; link=link->next) {
2205: if (link->interphook) {
2206: (*link->interphook)(coarse,interp,fine,link->ctx);
2207: }
2208: }
2209: return(0);
2210: }
2212: /*@
2213: DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2215: Collective on DM
2217: Input Arguments:
2218: + coarse - coarse DM
2219: . fine - fine DM
2220: . interp - (optional) the matrix computed by DMCreateInterpolation(). Implementations may not need this, but if it
2221: is available it can avoid some recomputation. If it is provided, MatInterpolate() will be used if
2222: the coarse DM does not have a specialized implementation.
2223: - coarseSol - solution on the coarse mesh
2225: Output Arguments:
2226: . fineSol - the interpolation of coarseSol to the fine mesh
2228: Level: developer
2230: Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2231: map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2232: out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2233: slope-limiting reconstruction.
2235: .seealso DMInterpolate(), DMCreateInterpolation()
2236: @*/
2237: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2238: {
2239: PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;
2249: PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2250: if (interpsol) {
2251: (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2252: } else if (interp) {
2253: MatInterpolate(interp, coarseSol, fineSol);
2254: } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2255: return(0);
2256: }
2258: /*@
2259: DMGetRefineLevel - Gets the number of refinements that have generated this DM.
2261: Not Collective
2263: Input Parameter:
2264: . dm - the DM object
2266: Output Parameter:
2267: . level - number of refinements
2269: Level: developer
2271: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2273: @*/
2274: PetscErrorCode DMGetRefineLevel(DM dm,PetscInt *level)
2275: {
2278: *level = dm->levelup;
2279: return(0);
2280: }
2282: /*@
2283: DMSetRefineLevel - Sets the number of refinements that have generated this DM.
2285: Not Collective
2287: Input Parameter:
2288: + dm - the DM object
2289: - level - number of refinements
2291: Level: advanced
2293: Notes:
2294: This value is used by PCMG to determine how many multigrid levels to use
2296: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2298: @*/
2299: PetscErrorCode DMSetRefineLevel(DM dm,PetscInt level)
2300: {
2303: dm->levelup = level;
2304: return(0);
2305: }
2307: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2308: {
2312: *tdm = dm->transformDM;
2313: return(0);
2314: }
2316: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2317: {
2321: *tv = dm->transform;
2322: return(0);
2323: }
2325: /*@
2326: DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors
2328: Input Parameter:
2329: . dm - The DM
2331: Output Parameter:
2332: . flg - PETSC_TRUE if a basis transformation should be done
2334: Level: developer
2336: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2337: @*/
2338: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2339: {
2340: Vec tv;
2346: DMGetBasisTransformVec_Internal(dm, &tv);
2347: *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2348: return(0);
2349: }
2351: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2352: {
2353: PetscSection s, ts;
2354: PetscScalar *ta;
2355: PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2359: DMGetCoordinateDim(dm, &cdim);
2360: DMGetLocalSection(dm, &s);
2361: PetscSectionGetChart(s, &pStart, &pEnd);
2362: PetscSectionGetNumFields(s, &Nf);
2363: DMClone(dm, &dm->transformDM);
2364: DMGetLocalSection(dm->transformDM, &ts);
2365: PetscSectionSetNumFields(ts, Nf);
2366: PetscSectionSetChart(ts, pStart, pEnd);
2367: for (f = 0; f < Nf; ++f) {
2368: PetscSectionGetFieldComponents(s, f, &Nc);
2369: /* We could start to label fields by their transformation properties */
2370: if (Nc != cdim) continue;
2371: for (p = pStart; p < pEnd; ++p) {
2372: PetscSectionGetFieldDof(s, p, f, &dof);
2373: if (!dof) continue;
2374: PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2375: PetscSectionAddDof(ts, p, PetscSqr(cdim));
2376: }
2377: }
2378: PetscSectionSetUp(ts);
2379: DMCreateLocalVector(dm->transformDM, &dm->transform);
2380: VecGetArray(dm->transform, &ta);
2381: for (p = pStart; p < pEnd; ++p) {
2382: for (f = 0; f < Nf; ++f) {
2383: PetscSectionGetFieldDof(ts, p, f, &dof);
2384: if (dof) {
2385: PetscReal x[3] = {0.0, 0.0, 0.0};
2386: PetscScalar *tva;
2387: const PetscScalar *A;
2389: /* TODO Get quadrature point for this dual basis vector for coordinate */
2390: (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2391: DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2392: PetscArraycpy(tva, A, PetscSqr(cdim));
2393: }
2394: }
2395: }
2396: VecRestoreArray(dm->transform, &ta);
2397: return(0);
2398: }
2400: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2401: {
2407: newdm->transformCtx = dm->transformCtx;
2408: newdm->transformSetUp = dm->transformSetUp;
2409: newdm->transformDestroy = NULL;
2410: newdm->transformGetMatrix = dm->transformGetMatrix;
2411: if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2412: return(0);
2413: }
2415: /*@C
2416: DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
2418: Logically Collective
2420: Input Arguments:
2421: + dm - the DM
2422: . beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2423: . endhook - function to run after DMGlobalToLocalEnd() has completed
2424: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2426: Calling sequence for beginhook:
2427: $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2429: + dm - global DM
2430: . g - global vector
2431: . mode - mode
2432: . l - local vector
2433: - ctx - optional user-defined function context
2436: Calling sequence for endhook:
2437: $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
2439: + global - global DM
2440: - ctx - optional user-defined function context
2442: Level: advanced
2444: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2445: @*/
2446: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2447: {
2448: PetscErrorCode ierr;
2449: DMGlobalToLocalHookLink link,*p;
2453: for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2454: PetscNew(&link);
2455: link->beginhook = beginhook;
2456: link->endhook = endhook;
2457: link->ctx = ctx;
2458: link->next = NULL;
2459: *p = link;
2460: return(0);
2461: }
2463: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2464: {
2465: Mat cMat;
2466: Vec cVec;
2467: PetscSection section, cSec;
2468: PetscInt pStart, pEnd, p, dof;
2473: DMGetDefaultConstraints(dm,&cSec,&cMat);
2474: if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2475: PetscInt nRows;
2477: MatGetSize(cMat,&nRows,NULL);
2478: if (nRows <= 0) return(0);
2479: DMGetLocalSection(dm,§ion);
2480: MatCreateVecs(cMat,NULL,&cVec);
2481: MatMult(cMat,l,cVec);
2482: PetscSectionGetChart(cSec,&pStart,&pEnd);
2483: for (p = pStart; p < pEnd; p++) {
2484: PetscSectionGetDof(cSec,p,&dof);
2485: if (dof) {
2486: PetscScalar *vals;
2487: VecGetValuesSection(cVec,cSec,p,&vals);
2488: VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2489: }
2490: }
2491: VecDestroy(&cVec);
2492: }
2493: return(0);
2494: }
2496: /*@
2497: DMGlobalToLocal - update local vectors from global vector
2499: Neighbor-wise Collective on dm
2501: Input Parameters:
2502: + dm - the DM object
2503: . g - the global vector
2504: . mode - INSERT_VALUES or ADD_VALUES
2505: - l - the local vector
2507: Notes:
2508: The communication involved in this update can be overlapped with computation by using
2509: DMGlobalToLocalBegin() and DMGlobalToLocalEnd().
2511: Level: beginner
2513: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2515: @*/
2516: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2517: {
2521: DMGlobalToLocalBegin(dm,g,mode,l);
2522: DMGlobalToLocalEnd(dm,g,mode,l);
2523: return(0);
2524: }
2526: /*@
2527: DMGlobalToLocalBegin - Begins updating local vectors from global vector
2529: Neighbor-wise Collective on dm
2531: Input Parameters:
2532: + dm - the DM object
2533: . g - the global vector
2534: . mode - INSERT_VALUES or ADD_VALUES
2535: - l - the local vector
2537: Level: intermediate
2539: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2541: @*/
2542: PetscErrorCode DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2543: {
2544: PetscSF sf;
2545: PetscErrorCode ierr;
2546: DMGlobalToLocalHookLink link;
2551: for (link=dm->gtolhook; link; link=link->next) {
2552: if (link->beginhook) {
2553: (*link->beginhook)(dm,g,mode,l,link->ctx);
2554: }
2555: }
2556: DMGetSectionSF(dm, &sf);
2557: if (sf) {
2558: const PetscScalar *gArray;
2559: PetscScalar *lArray;
2560: PetscMemType lmtype,gmtype;
2562: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2563: VecGetArrayAndMemType(l, &lArray, &lmtype);
2564: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2565: PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2566: VecRestoreArrayAndMemType(l, &lArray);
2567: VecRestoreArrayReadAndMemType(g, &gArray);
2568: } else {
2569: if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2570: (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2571: }
2572: return(0);
2573: }
2575: /*@
2576: DMGlobalToLocalEnd - Ends updating local vectors from global vector
2578: Neighbor-wise Collective on dm
2580: Input Parameters:
2581: + dm - the DM object
2582: . g - the global vector
2583: . mode - INSERT_VALUES or ADD_VALUES
2584: - l - the local vector
2586: Level: intermediate
2588: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()
2590: @*/
2591: PetscErrorCode DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2592: {
2593: PetscSF sf;
2594: PetscErrorCode ierr;
2595: const PetscScalar *gArray;
2596: PetscScalar *lArray;
2597: PetscBool transform;
2598: DMGlobalToLocalHookLink link;
2599: PetscMemType lmtype,gmtype;
2603: DMGetSectionSF(dm, &sf);
2604: DMHasBasisTransform(dm, &transform);
2605: if (sf) {
2606: if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2608: VecGetArrayAndMemType(l, &lArray, &lmtype);
2609: VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2610: PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2611: VecRestoreArrayAndMemType(l, &lArray);
2612: VecRestoreArrayReadAndMemType(g, &gArray);
2613: if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2614: } else {
2615: if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2616: (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2617: }
2618: DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2619: for (link=dm->gtolhook; link; link=link->next) {
2620: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2621: }
2622: return(0);
2623: }
2625: /*@C
2626: DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2628: Logically Collective
2630: Input Arguments:
2631: + dm - the DM
2632: . beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2633: . endhook - function to run after DMLocalToGlobalEnd() has completed
2634: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2636: Calling sequence for beginhook:
2637: $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2639: + dm - global DM
2640: . l - local vector
2641: . mode - mode
2642: . g - global vector
2643: - ctx - optional user-defined function context
2646: Calling sequence for endhook:
2647: $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
2649: + global - global DM
2650: . l - local vector
2651: . mode - mode
2652: . g - global vector
2653: - ctx - optional user-defined function context
2655: Level: advanced
2657: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2658: @*/
2659: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2660: {
2661: PetscErrorCode ierr;
2662: DMLocalToGlobalHookLink link,*p;
2666: for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2667: PetscNew(&link);
2668: link->beginhook = beginhook;
2669: link->endhook = endhook;
2670: link->ctx = ctx;
2671: link->next = NULL;
2672: *p = link;
2673: return(0);
2674: }
2676: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2677: {
2678: Mat cMat;
2679: Vec cVec;
2680: PetscSection section, cSec;
2681: PetscInt pStart, pEnd, p, dof;
2686: DMGetDefaultConstraints(dm,&cSec,&cMat);
2687: if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2688: PetscInt nRows;
2690: MatGetSize(cMat,&nRows,NULL);
2691: if (nRows <= 0) return(0);
2692: DMGetLocalSection(dm,§ion);
2693: MatCreateVecs(cMat,NULL,&cVec);
2694: PetscSectionGetChart(cSec,&pStart,&pEnd);
2695: for (p = pStart; p < pEnd; p++) {
2696: PetscSectionGetDof(cSec,p,&dof);
2697: if (dof) {
2698: PetscInt d;
2699: PetscScalar *vals;
2700: VecGetValuesSection(l,section,p,&vals);
2701: VecSetValuesSection(cVec,cSec,p,vals,mode);
2702: /* for this to be the true transpose, we have to zero the values that
2703: * we just extracted */
2704: for (d = 0; d < dof; d++) {
2705: vals[d] = 0.;
2706: }
2707: }
2708: }
2709: MatMultTransposeAdd(cMat,cVec,l,l);
2710: VecDestroy(&cVec);
2711: }
2712: return(0);
2713: }
2714: /*@
2715: DMLocalToGlobal - updates global vectors from local vectors
2717: Neighbor-wise Collective on dm
2719: Input Parameters:
2720: + dm - the DM object
2721: . l - the local vector
2722: . 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.
2723: - g - the global vector
2725: Notes:
2726: The communication involved in this update can be overlapped with computation by using
2727: DMLocalToGlobalBegin() and DMLocalToGlobalEnd().
2729: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2730: INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.
2732: Level: beginner
2734: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2736: @*/
2737: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2738: {
2742: DMLocalToGlobalBegin(dm,l,mode,g);
2743: DMLocalToGlobalEnd(dm,l,mode,g);
2744: return(0);
2745: }
2747: /*@
2748: DMLocalToGlobalBegin - begins updating global vectors from local vectors
2750: Neighbor-wise Collective on dm
2752: Input Parameters:
2753: + dm - the DM object
2754: . l - the local vector
2755: . 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.
2756: - g - the global vector
2758: Notes:
2759: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2760: INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
2762: Level: intermediate
2764: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
2766: @*/
2767: PetscErrorCode DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2768: {
2769: PetscSF sf;
2770: PetscSection s, gs;
2771: DMLocalToGlobalHookLink link;
2772: Vec tmpl;
2773: const PetscScalar *lArray;
2774: PetscScalar *gArray;
2775: PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2776: PetscErrorCode ierr;
2777: PetscMemType lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;
2781: for (link=dm->ltoghook; link; link=link->next) {
2782: if (link->beginhook) {
2783: (*link->beginhook)(dm,l,mode,g,link->ctx);
2784: }
2785: }
2786: DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2787: DMGetSectionSF(dm, &sf);
2788: DMGetLocalSection(dm, &s);
2789: switch (mode) {
2790: case INSERT_VALUES:
2791: case INSERT_ALL_VALUES:
2792: case INSERT_BC_VALUES:
2793: isInsert = PETSC_TRUE; break;
2794: case ADD_VALUES:
2795: case ADD_ALL_VALUES:
2796: case ADD_BC_VALUES:
2797: isInsert = PETSC_FALSE; break;
2798: default:
2799: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2800: }
2801: if ((sf && !isInsert) || (s && isInsert)) {
2802: DMHasBasisTransform(dm, &transform);
2803: if (transform) {
2804: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2805: VecCopy(l, tmpl);
2806: DMPlexLocalToGlobalBasis(dm, tmpl);
2807: VecGetArrayRead(tmpl, &lArray);
2808: } else if (isInsert) {
2809: VecGetArrayRead(l, &lArray);
2810: } else {
2811: VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2812: l_inplace = PETSC_TRUE;
2813: }
2814: if (s && isInsert) {
2815: VecGetArray(g, &gArray);
2816: } else {
2817: VecGetArrayAndMemType(g, &gArray, &gmtype);
2818: g_inplace = PETSC_TRUE;
2819: }
2820: if (sf && !isInsert) {
2821: PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2822: } else if (s && isInsert) {
2823: PetscInt gStart, pStart, pEnd, p;
2825: DMGetGlobalSection(dm, &gs);
2826: PetscSectionGetChart(s, &pStart, &pEnd);
2827: VecGetOwnershipRange(g, &gStart, NULL);
2828: for (p = pStart; p < pEnd; ++p) {
2829: PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2831: PetscSectionGetDof(s, p, &dof);
2832: PetscSectionGetDof(gs, p, &gdof);
2833: PetscSectionGetConstraintDof(s, p, &cdof);
2834: PetscSectionGetConstraintDof(gs, p, &gcdof);
2835: PetscSectionGetOffset(s, p, &off);
2836: PetscSectionGetOffset(gs, p, &goff);
2837: /* Ignore off-process data and points with no global data */
2838: if (!gdof || goff < 0) continue;
2839: 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);
2840: /* If no constraints are enforced in the global vector */
2841: if (!gcdof) {
2842: for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2843: /* If constraints are enforced in the global vector */
2844: } else if (cdof == gcdof) {
2845: const PetscInt *cdofs;
2846: PetscInt cind = 0;
2848: PetscSectionGetConstraintIndices(s, p, &cdofs);
2849: for (d = 0, e = 0; d < dof; ++d) {
2850: if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2851: gArray[goff-gStart+e++] = lArray[off+d];
2852: }
2853: } 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);
2854: }
2855: }
2856: if (g_inplace) {
2857: VecRestoreArrayAndMemType(g, &gArray);
2858: } else {
2859: VecRestoreArray(g, &gArray);
2860: }
2861: if (transform) {
2862: VecRestoreArrayRead(tmpl, &lArray);
2863: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2864: } else if (l_inplace) {
2865: VecRestoreArrayReadAndMemType(l, &lArray);
2866: } else {
2867: VecRestoreArrayRead(l, &lArray);
2868: }
2869: } else {
2870: if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2871: (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2872: }
2873: return(0);
2874: }
2876: /*@
2877: DMLocalToGlobalEnd - updates global vectors from local vectors
2879: Neighbor-wise Collective on dm
2881: Input Parameters:
2882: + dm - the DM object
2883: . l - the local vector
2884: . mode - INSERT_VALUES or ADD_VALUES
2885: - g - the global vector
2887: Level: intermediate
2889: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2891: @*/
2892: PetscErrorCode DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2893: {
2894: PetscSF sf;
2895: PetscSection s;
2896: DMLocalToGlobalHookLink link;
2897: PetscBool isInsert, transform;
2898: PetscErrorCode ierr;
2902: DMGetSectionSF(dm, &sf);
2903: DMGetLocalSection(dm, &s);
2904: switch (mode) {
2905: case INSERT_VALUES:
2906: case INSERT_ALL_VALUES:
2907: isInsert = PETSC_TRUE; break;
2908: case ADD_VALUES:
2909: case ADD_ALL_VALUES:
2910: isInsert = PETSC_FALSE; break;
2911: default:
2912: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2913: }
2914: if (sf && !isInsert) {
2915: const PetscScalar *lArray;
2916: PetscScalar *gArray;
2917: Vec tmpl;
2919: DMHasBasisTransform(dm, &transform);
2920: if (transform) {
2921: DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2922: VecGetArrayRead(tmpl, &lArray);
2923: } else {
2924: VecGetArrayReadAndMemType(l, &lArray, NULL);
2925: }
2926: VecGetArrayAndMemType(g, &gArray, NULL);
2927: PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2928: if (transform) {
2929: VecRestoreArrayRead(tmpl, &lArray);
2930: DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2931: } else {
2932: VecRestoreArrayReadAndMemType(l, &lArray);
2933: }
2934: VecRestoreArrayAndMemType(g, &gArray);
2935: } else if (s && isInsert) {
2936: } else {
2937: if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2938: (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2939: }
2940: for (link=dm->ltoghook; link; link=link->next) {
2941: if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2942: }
2943: return(0);
2944: }
2946: /*@
2947: DMLocalToLocalBegin - Maps from a local vector (including ghost points
2948: that contain irrelevant values) to another local vector where the ghost
2949: points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2951: Neighbor-wise Collective on dm
2953: Input Parameters:
2954: + dm - the DM object
2955: . g - the original local vector
2956: - mode - one of INSERT_VALUES or ADD_VALUES
2958: Output Parameter:
2959: . l - the local vector with correct ghost values
2961: Level: intermediate
2963: Notes:
2964: The local vectors used here need not be the same as those
2965: obtained from DMCreateLocalVector(), BUT they
2966: must have the same parallel data layout; they could, for example, be
2967: obtained with VecDuplicate() from the DM originating vectors.
2969: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2971: @*/
2972: PetscErrorCode DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2973: {
2974: PetscErrorCode ierr;
2978: if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2979: (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2980: return(0);
2981: }
2983: /*@
2984: DMLocalToLocalEnd - Maps from a local vector (including ghost points
2985: that contain irrelevant values) to another local vector where the ghost
2986: points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2988: Neighbor-wise Collective on dm
2990: Input Parameters:
2991: + da - the DM object
2992: . g - the original local vector
2993: - mode - one of INSERT_VALUES or ADD_VALUES
2995: Output Parameter:
2996: . l - the local vector with correct ghost values
2998: Level: intermediate
3000: Notes:
3001: The local vectors used here need not be the same as those
3002: obtained from DMCreateLocalVector(), BUT they
3003: must have the same parallel data layout; they could, for example, be
3004: obtained with VecDuplicate() from the DM originating vectors.
3006: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
3008: @*/
3009: PetscErrorCode DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3010: {
3011: PetscErrorCode ierr;
3015: if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
3016: (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3017: return(0);
3018: }
3021: /*@
3022: DMCoarsen - Coarsens a DM object
3024: Collective on dm
3026: Input Parameter:
3027: + dm - the DM object
3028: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
3030: Output Parameter:
3031: . dmc - the coarsened DM
3033: Level: developer
3035: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3037: @*/
3038: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3039: {
3040: PetscErrorCode ierr;
3041: DMCoarsenHookLink link;
3045: if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
3046: PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3047: (*dm->ops->coarsen)(dm, comm, dmc);
3048: if (*dmc) {
3049: DMSetCoarseDM(dm,*dmc);
3050: (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3051: PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3052: (*dmc)->ctx = dm->ctx;
3053: (*dmc)->levelup = dm->levelup;
3054: (*dmc)->leveldown = dm->leveldown + 1;
3055: DMSetMatType(*dmc,dm->mattype);
3056: for (link=dm->coarsenhook; link; link=link->next) {
3057: if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3058: }
3059: }
3060: PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3061: if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3062: return(0);
3063: }
3065: /*@C
3066: DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3068: Logically Collective
3070: Input Arguments:
3071: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3072: . coarsenhook - function to run when setting up a coarser level
3073: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3074: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3076: Calling sequence of coarsenhook:
3077: $ coarsenhook(DM fine,DM coarse,void *ctx);
3079: + fine - fine level DM
3080: . coarse - coarse level DM to restrict problem to
3081: - ctx - optional user-defined function context
3083: Calling sequence for restricthook:
3084: $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3086: + fine - fine level DM
3087: . mrestrict - matrix restricting a fine-level solution to the coarse grid
3088: . rscale - scaling vector for restriction
3089: . inject - matrix restricting by injection
3090: . coarse - coarse level DM to update
3091: - ctx - optional user-defined function context
3093: Level: advanced
3095: Notes:
3096: This function is only needed if auxiliary data needs to be set up on coarse grids.
3098: If this function is called multiple times, the hooks will be run in the order they are added.
3100: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3101: extract the finest level information from its context (instead of from the SNES).
3103: This function is currently not available from Fortran.
3105: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3106: @*/
3107: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3108: {
3109: PetscErrorCode ierr;
3110: DMCoarsenHookLink link,*p;
3114: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3115: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3116: }
3117: PetscNew(&link);
3118: link->coarsenhook = coarsenhook;
3119: link->restricthook = restricthook;
3120: link->ctx = ctx;
3121: link->next = NULL;
3122: *p = link;
3123: return(0);
3124: }
3126: /*@C
3127: DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid
3129: Logically Collective
3131: Input Arguments:
3132: + fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3133: . coarsenhook - function to run when setting up a coarser level
3134: . restricthook - function to run to update data on coarser levels (once per SNESSolve())
3135: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3137: Level: advanced
3139: Notes:
3140: This function does nothing if the hook is not in the list.
3142: This function is currently not available from Fortran.
3144: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3145: @*/
3146: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3147: {
3148: PetscErrorCode ierr;
3149: DMCoarsenHookLink link,*p;
3153: for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3154: if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3155: link = *p;
3156: *p = link->next;
3157: PetscFree(link);
3158: break;
3159: }
3160: }
3161: return(0);
3162: }
3165: /*@
3166: DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
3168: Collective if any hooks are
3170: Input Arguments:
3171: + fine - finer DM to use as a base
3172: . restrct - restriction matrix, apply using MatRestrict()
3173: . rscale - scaling vector for restriction
3174: . inject - injection matrix, also use MatRestrict()
3175: - coarse - coarser DM to update
3177: Level: developer
3179: .seealso: DMCoarsenHookAdd(), MatRestrict()
3180: @*/
3181: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3182: {
3183: PetscErrorCode ierr;
3184: DMCoarsenHookLink link;
3187: for (link=fine->coarsenhook; link; link=link->next) {
3188: if (link->restricthook) {
3189: (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3190: }
3191: }
3192: return(0);
3193: }
3195: /*@C
3196: DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3198: Logically Collective on global
3200: Input Arguments:
3201: + global - global DM
3202: . ddhook - function to run to pass data to the decomposition DM upon its creation
3203: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3204: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3207: Calling sequence for ddhook:
3208: $ ddhook(DM global,DM block,void *ctx)
3210: + global - global DM
3211: . block - block DM
3212: - ctx - optional user-defined function context
3214: Calling sequence for restricthook:
3215: $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3217: + global - global DM
3218: . out - scatter to the outer (with ghost and overlap points) block vector
3219: . in - scatter to block vector values only owned locally
3220: . block - block DM
3221: - ctx - optional user-defined function context
3223: Level: advanced
3225: Notes:
3226: This function is only needed if auxiliary data needs to be set up on subdomain DMs.
3228: If this function is called multiple times, the hooks will be run in the order they are added.
3230: In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3231: extract the global information from its context (instead of from the SNES).
3233: This function is currently not available from Fortran.
3235: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3236: @*/
3237: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3238: {
3239: PetscErrorCode ierr;
3240: DMSubDomainHookLink link,*p;
3244: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3245: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3246: }
3247: PetscNew(&link);
3248: link->restricthook = restricthook;
3249: link->ddhook = ddhook;
3250: link->ctx = ctx;
3251: link->next = NULL;
3252: *p = link;
3253: return(0);
3254: }
3256: /*@C
3257: DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3259: Logically Collective
3261: Input Arguments:
3262: + global - global DM
3263: . ddhook - function to run to pass data to the decomposition DM upon its creation
3264: . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3265: - ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3267: Level: advanced
3269: Notes:
3271: This function is currently not available from Fortran.
3273: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3274: @*/
3275: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3276: {
3277: PetscErrorCode ierr;
3278: DMSubDomainHookLink link,*p;
3282: for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3283: if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3284: link = *p;
3285: *p = link->next;
3286: PetscFree(link);
3287: break;
3288: }
3289: }
3290: return(0);
3291: }
3293: /*@
3294: DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
3296: Collective if any hooks are
3298: Input Arguments:
3299: + fine - finer DM to use as a base
3300: . oscatter - scatter from domain global vector filling subdomain global vector with overlap
3301: . gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3302: - coarse - coarer DM to update
3304: Level: developer
3306: .seealso: DMCoarsenHookAdd(), MatRestrict()
3307: @*/
3308: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3309: {
3310: PetscErrorCode ierr;
3311: DMSubDomainHookLink link;
3314: for (link=global->subdomainhook; link; link=link->next) {
3315: if (link->restricthook) {
3316: (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3317: }
3318: }
3319: return(0);
3320: }
3322: /*@
3323: DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
3325: Not Collective
3327: Input Parameter:
3328: . dm - the DM object
3330: Output Parameter:
3331: . level - number of coarsenings
3333: Level: developer
3335: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3337: @*/
3338: PetscErrorCode DMGetCoarsenLevel(DM dm,PetscInt *level)
3339: {
3343: *level = dm->leveldown;
3344: return(0);
3345: }
3347: /*@
3348: DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.
3350: Not Collective
3352: Input Parameters:
3353: + dm - the DM object
3354: - level - number of coarsenings
3356: Level: developer
3358: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3359: @*/
3360: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3361: {
3364: dm->leveldown = level;
3365: return(0);
3366: }
3370: /*@C
3371: DMRefineHierarchy - Refines a DM object, all levels at once
3373: Collective on dm
3375: Input Parameter:
3376: + dm - the DM object
3377: - nlevels - the number of levels of refinement
3379: Output Parameter:
3380: . dmf - the refined DM hierarchy
3382: Level: developer
3384: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3386: @*/
3387: PetscErrorCode DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3388: {
3393: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3394: if (nlevels == 0) return(0);
3396: if (dm->ops->refinehierarchy) {
3397: (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3398: } else if (dm->ops->refine) {
3399: PetscInt i;
3401: DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3402: for (i=1; i<nlevels; i++) {
3403: DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3404: }
3405: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3406: return(0);
3407: }
3409: /*@C
3410: DMCoarsenHierarchy - Coarsens a DM object, all levels at once
3412: Collective on dm
3414: Input Parameter:
3415: + dm - the DM object
3416: - nlevels - the number of levels of coarsening
3418: Output Parameter:
3419: . dmc - the coarsened DM hierarchy
3421: Level: developer
3423: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3425: @*/
3426: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3427: {
3432: if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3433: if (nlevels == 0) return(0);
3435: if (dm->ops->coarsenhierarchy) {
3436: (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3437: } else if (dm->ops->coarsen) {
3438: PetscInt i;
3440: DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3441: for (i=1; i<nlevels; i++) {
3442: DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3443: }
3444: } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3445: return(0);
3446: }
3448: /*@C
3449: DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
3451: Not Collective
3453: Input Parameters:
3454: + dm - the DM object
3455: - destroy - the destroy function
3457: Level: intermediate
3459: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3461: @*/
3462: PetscErrorCode DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3463: {
3466: dm->ctxdestroy = destroy;
3467: return(0);
3468: }
3470: /*@
3471: DMSetApplicationContext - Set a user context into a DM object
3473: Not Collective
3475: Input Parameters:
3476: + dm - the DM object
3477: - ctx - the user context
3479: Level: intermediate
3481: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3483: @*/
3484: PetscErrorCode DMSetApplicationContext(DM dm,void *ctx)
3485: {
3488: dm->ctx = ctx;
3489: return(0);
3490: }
3492: /*@
3493: DMGetApplicationContext - Gets a user context from a DM object
3495: Not Collective
3497: Input Parameter:
3498: . dm - the DM object
3500: Output Parameter:
3501: . ctx - the user context
3503: Level: intermediate
3505: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3507: @*/
3508: PetscErrorCode DMGetApplicationContext(DM dm,void *ctx)
3509: {
3512: *(void**)ctx = dm->ctx;
3513: return(0);
3514: }
3516: /*@C
3517: DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
3519: Logically Collective on dm
3521: Input Parameter:
3522: + dm - the DM object
3523: - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3525: Level: intermediate
3527: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3528: DMSetJacobian()
3530: @*/
3531: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3532: {
3535: dm->ops->computevariablebounds = f;
3536: return(0);
3537: }
3539: /*@
3540: DMHasVariableBounds - does the DM object have a variable bounds function?
3542: Not Collective
3544: Input Parameter:
3545: . dm - the DM object to destroy
3547: Output Parameter:
3548: . flg - PETSC_TRUE if the variable bounds function exists
3550: Level: developer
3552: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3554: @*/
3555: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3556: {
3560: *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3561: return(0);
3562: }
3564: /*@C
3565: DMComputeVariableBounds - compute variable bounds used by SNESVI.
3567: Logically Collective on dm
3569: Input Parameters:
3570: . dm - the DM object
3572: Output parameters:
3573: + xl - lower bound
3574: - xu - upper bound
3576: Level: advanced
3578: Notes:
3579: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3581: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
3583: @*/
3584: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3585: {
3592: if (!dm->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeVariableBounds",((PetscObject)dm)->type_name);
3593: (*dm->ops->computevariablebounds)(dm, xl,xu);
3594: return(0);
3595: }
3597: /*@
3598: DMHasColoring - does the DM object have a method of providing a coloring?
3600: Not Collective
3602: Input Parameter:
3603: . dm - the DM object
3605: Output Parameter:
3606: . flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
3608: Level: developer
3610: .seealso DMCreateColoring()
3612: @*/
3613: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3614: {
3618: *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3619: return(0);
3620: }
3622: /*@
3623: DMHasCreateRestriction - does the DM object have a method of providing a restriction?
3625: Not Collective
3627: Input Parameter:
3628: . dm - the DM object
3630: Output Parameter:
3631: . flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().
3633: Level: developer
3635: .seealso DMCreateRestriction()
3637: @*/
3638: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3639: {
3643: *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3644: return(0);
3645: }
3648: /*@
3649: DMHasCreateInjection - does the DM object have a method of providing an injection?
3651: Not Collective
3653: Input Parameter:
3654: . dm - the DM object
3656: Output Parameter:
3657: . flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().
3659: Level: developer
3661: .seealso DMCreateInjection()
3663: @*/
3664: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3665: {
3671: if (dm->ops->hascreateinjection) {
3672: (*dm->ops->hascreateinjection)(dm,flg);
3673: } else {
3674: *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3675: }
3676: return(0);
3677: }
3679: PetscFunctionList DMList = NULL;
3680: PetscBool DMRegisterAllCalled = PETSC_FALSE;
3682: /*@C
3683: DMSetType - Builds a DM, for a particular DM implementation.
3685: Collective on dm
3687: Input Parameters:
3688: + dm - The DM object
3689: - method - The name of the DM type
3691: Options Database Key:
3692: . -dm_type <type> - Sets the DM type; use -help for a list of available types
3694: Notes:
3695: See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
3697: Level: intermediate
3699: .seealso: DMGetType(), DMCreate()
3700: @*/
3701: PetscErrorCode DMSetType(DM dm, DMType method)
3702: {
3703: PetscErrorCode (*r)(DM);
3704: PetscBool match;
3709: PetscObjectTypeCompare((PetscObject) dm, method, &match);
3710: if (match) return(0);
3712: DMRegisterAll();
3713: PetscFunctionListFind(DMList,method,&r);
3714: if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3716: if (dm->ops->destroy) {
3717: (*dm->ops->destroy)(dm);
3718: }
3719: PetscMemzero(dm->ops,sizeof(*dm->ops));
3720: PetscObjectChangeTypeName((PetscObject)dm,method);
3721: (*r)(dm);
3722: return(0);
3723: }
3725: /*@C
3726: DMGetType - Gets the DM type name (as a string) from the DM.
3728: Not Collective
3730: Input Parameter:
3731: . dm - The DM
3733: Output Parameter:
3734: . type - The DM type name
3736: Level: intermediate
3738: .seealso: DMSetType(), DMCreate()
3739: @*/
3740: PetscErrorCode DMGetType(DM dm, DMType *type)
3741: {
3747: DMRegisterAll();
3748: *type = ((PetscObject)dm)->type_name;
3749: return(0);
3750: }
3752: /*@C
3753: DMConvert - Converts a DM to another DM, either of the same or different type.
3755: Collective on dm
3757: Input Parameters:
3758: + dm - the DM
3759: - newtype - new DM type (use "same" for the same type)
3761: Output Parameter:
3762: . M - pointer to new DM
3764: Notes:
3765: Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3766: the MPI communicator of the generated DM is always the same as the communicator
3767: of the input DM.
3769: Level: intermediate
3771: .seealso: DMCreate()
3772: @*/
3773: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3774: {
3775: DM B;
3776: char convname[256];
3777: PetscBool sametype/*, issame */;
3784: PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3785: /* PetscStrcmp(newtype, "same", &issame); */
3786: if (sametype) {
3787: *M = dm;
3788: PetscObjectReference((PetscObject) dm);
3789: return(0);
3790: } else {
3791: PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
3793: /*
3794: Order of precedence:
3795: 1) See if a specialized converter is known to the current DM.
3796: 2) See if a specialized converter is known to the desired DM class.
3797: 3) See if a good general converter is registered for the desired class
3798: 4) See if a good general converter is known for the current matrix.
3799: 5) Use a really basic converter.
3800: */
3802: /* 1) See if a specialized converter is known to the current DM and the desired class */
3803: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3804: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3805: PetscStrlcat(convname,"_",sizeof(convname));
3806: PetscStrlcat(convname,newtype,sizeof(convname));
3807: PetscStrlcat(convname,"_C",sizeof(convname));
3808: PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3809: if (conv) goto foundconv;
3811: /* 2) See if a specialized converter is known to the desired DM class. */
3812: DMCreate(PetscObjectComm((PetscObject)dm), &B);
3813: DMSetType(B, newtype);
3814: PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3815: PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3816: PetscStrlcat(convname,"_",sizeof(convname));
3817: PetscStrlcat(convname,newtype,sizeof(convname));
3818: PetscStrlcat(convname,"_C",sizeof(convname));
3819: PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3820: if (conv) {
3821: DMDestroy(&B);
3822: goto foundconv;
3823: }
3825: #if 0
3826: /* 3) See if a good general converter is registered for the desired class */
3827: conv = B->ops->convertfrom;
3828: DMDestroy(&B);
3829: if (conv) goto foundconv;
3831: /* 4) See if a good general converter is known for the current matrix */
3832: if (dm->ops->convert) {
3833: conv = dm->ops->convert;
3834: }
3835: if (conv) goto foundconv;
3836: #endif
3838: /* 5) Use a really basic converter. */
3839: SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
3841: foundconv:
3842: PetscLogEventBegin(DM_Convert,dm,0,0,0);
3843: (*conv)(dm,newtype,M);
3844: /* Things that are independent of DM type: We should consult DMClone() here */
3845: {
3846: PetscBool isper;
3847: const PetscReal *maxCell, *L;
3848: const DMBoundaryType *bd;
3849: DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3850: DMSetPeriodicity(*M, isper, maxCell, L, bd);
3851: (*M)->prealloc_only = dm->prealloc_only;
3852: PetscFree((*M)->vectype);
3853: PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3854: PetscFree((*M)->mattype);
3855: PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3856: }
3857: PetscLogEventEnd(DM_Convert,dm,0,0,0);
3858: }
3859: PetscObjectStateIncrease((PetscObject) *M);
3860: return(0);
3861: }
3863: /*--------------------------------------------------------------------------------------------------------------------*/
3865: /*@C
3866: DMRegister - Adds a new DM component implementation
3868: Not Collective
3870: Input Parameters:
3871: + name - The name of a new user-defined creation routine
3872: - create_func - The creation routine itself
3874: Notes:
3875: DMRegister() may be called multiple times to add several user-defined DMs
3878: Sample usage:
3879: .vb
3880: DMRegister("my_da", MyDMCreate);
3881: .ve
3883: Then, your DM type can be chosen with the procedural interface via
3884: .vb
3885: DMCreate(MPI_Comm, DM *);
3886: DMSetType(DM,"my_da");
3887: .ve
3888: or at runtime via the option
3889: .vb
3890: -da_type my_da
3891: .ve
3893: Level: advanced
3895: .seealso: DMRegisterAll(), DMRegisterDestroy()
3897: @*/
3898: PetscErrorCode DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3899: {
3903: DMInitializePackage();
3904: PetscFunctionListAdd(&DMList,sname,function);
3905: return(0);
3906: }
3908: /*@C
3909: DMLoad - Loads a DM that has been stored in binary with DMView().
3911: Collective on viewer
3913: Input Parameters:
3914: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3915: some related function before a call to DMLoad().
3916: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3917: HDF5 file viewer, obtained from PetscViewerHDF5Open()
3919: Level: intermediate
3921: Notes:
3922: The type is determined by the data in the file, any type set into the DM before this call is ignored.
3924: Notes for advanced users:
3925: Most users should not need to know the details of the binary storage
3926: format, since DMLoad() and DMView() completely hide these details.
3927: But for anyone who's interested, the standard binary matrix storage
3928: format is
3929: .vb
3930: has not yet been determined
3931: .ve
3933: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3934: @*/
3935: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
3936: {
3937: PetscBool isbinary, ishdf5;
3943: PetscViewerCheckReadable(viewer);
3944: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3945: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3946: PetscLogEventBegin(DM_Load,viewer,0,0,0);
3947: if (isbinary) {
3948: PetscInt classid;
3949: char type[256];
3951: PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3952: if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3953: PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3954: DMSetType(newdm, type);
3955: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3956: } else if (ishdf5) {
3957: if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3958: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3959: PetscLogEventEnd(DM_Load,viewer,0,0,0);
3960: return(0);
3961: }
3963: /*@
3964: DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.
3966: Not collective
3968: Input Parameter:
3969: . dm - the DM
3971: Output Parameters:
3972: + lmin - local minimum coordinates (length coord dim, optional)
3973: - lmax - local maximim coordinates (length coord dim, optional)
3975: Level: beginner
3977: Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.
3980: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3981: @*/
3982: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3983: {
3984: Vec coords = NULL;
3985: PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3986: PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3987: const PetscScalar *local_coords;
3988: PetscInt N, Ni;
3989: PetscInt cdim, i, j;
3990: PetscErrorCode ierr;
3994: DMGetCoordinateDim(dm, &cdim);
3995: DMGetCoordinates(dm, &coords);
3996: if (coords) {
3997: VecGetArrayRead(coords, &local_coords);
3998: VecGetLocalSize(coords, &N);
3999: Ni = N/cdim;
4000: for (i = 0; i < Ni; ++i) {
4001: for (j = 0; j < 3; ++j) {
4002: min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4003: max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4004: }
4005: }
4006: VecRestoreArrayRead(coords, &local_coords);
4007: } else {
4008: PetscBool isda;
4010: PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4011: if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4012: }
4013: if (lmin) {PetscArraycpy(lmin, min, cdim);}
4014: if (lmax) {PetscArraycpy(lmax, max, cdim);}
4015: return(0);
4016: }
4018: /*@
4019: DMGetBoundingBox - Returns the global bounding box for the DM.
4021: Collective
4023: Input Parameter:
4024: . dm - the DM
4026: Output Parameters:
4027: + gmin - global minimum coordinates (length coord dim, optional)
4028: - gmax - global maximim coordinates (length coord dim, optional)
4030: Level: beginner
4032: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4033: @*/
4034: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4035: {
4036: PetscReal lmin[3], lmax[3];
4037: PetscInt cdim;
4038: PetscMPIInt count;
4043: DMGetCoordinateDim(dm, &cdim);
4044: PetscMPIIntCast(cdim, &count);
4045: DMGetLocalBoundingBox(dm, lmin, lmax);
4046: if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4047: if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4048: return(0);
4049: }
4051: /******************************** FEM Support **********************************/
4053: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4054: {
4055: PetscInt f;
4059: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4060: for (f = 0; f < len; ++f) {
4061: PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]));
4062: }
4063: return(0);
4064: }
4066: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4067: {
4068: PetscInt f, g;
4072: PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4073: for (f = 0; f < rows; ++f) {
4074: PetscPrintf(PETSC_COMM_SELF, " |");
4075: for (g = 0; g < cols; ++g) {
4076: PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4077: }
4078: PetscPrintf(PETSC_COMM_SELF, " |\n");
4079: }
4080: return(0);
4081: }
4083: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4084: {
4085: PetscInt localSize, bs;
4086: PetscMPIInt size;
4087: Vec x, xglob;
4088: const PetscScalar *xarray;
4089: PetscErrorCode ierr;
4092: MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4093: VecDuplicate(X, &x);
4094: VecCopy(X, x);
4095: VecChop(x, tol);
4096: PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4097: if (size > 1) {
4098: VecGetLocalSize(x,&localSize);
4099: VecGetArrayRead(x,&xarray);
4100: VecGetBlockSize(x,&bs);
4101: VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4102: } else {
4103: xglob = x;
4104: }
4105: VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4106: if (size > 1) {
4107: VecDestroy(&xglob);
4108: VecRestoreArrayRead(x,&xarray);
4109: }
4110: VecDestroy(&x);
4111: return(0);
4112: }
4114: /*@
4115: DMGetSection - Get the PetscSection encoding the local data layout for the DM. This is equivalent to DMGetLocalSection(). Deprecated in v3.12
4117: Input Parameter:
4118: . dm - The DM
4120: Output Parameter:
4121: . section - The PetscSection
4123: Options Database Keys:
4124: . -dm_petscsection_view - View the Section created by the DM
4126: Level: advanced
4128: Notes:
4129: Use DMGetLocalSection() in new code.
4131: This gets a borrowed reference, so the user should not destroy this PetscSection.
4133: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4134: @*/
4135: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4136: {
4140: DMGetLocalSection(dm,section);
4141: return(0);
4142: }
4144: /*@
4145: DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
4147: Input Parameter:
4148: . dm - The DM
4150: Output Parameter:
4151: . section - The PetscSection
4153: Options Database Keys:
4154: . -dm_petscsection_view - View the Section created by the DM
4156: Level: intermediate
4158: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4160: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4161: @*/
4162: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4163: {
4169: if (!dm->localSection && dm->ops->createlocalsection) {
4170: PetscInt d;
4172: if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4173: (*dm->ops->createlocalsection)(dm);
4174: if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4175: }
4176: *section = dm->localSection;
4177: return(0);
4178: }
4180: /*@
4181: DMSetSection - Set the PetscSection encoding the local data layout for the DM. This is equivalent to DMSetLocalSection(). Deprecated in v3.12
4183: Input Parameters:
4184: + dm - The DM
4185: - section - The PetscSection
4187: Level: advanced
4189: Notes:
4190: Use DMSetLocalSection() in new code.
4192: Any existing Section will be destroyed
4194: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4195: @*/
4196: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4197: {
4201: DMSetLocalSection(dm,section);
4202: return(0);
4203: }
4205: /*@
4206: DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
4208: Input Parameters:
4209: + dm - The DM
4210: - section - The PetscSection
4212: Level: intermediate
4214: Note: Any existing Section will be destroyed
4216: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4217: @*/
4218: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4219: {
4220: PetscInt numFields = 0;
4221: PetscInt f;
4227: PetscObjectReference((PetscObject)section);
4228: PetscSectionDestroy(&dm->localSection);
4229: dm->localSection = section;
4230: if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4231: if (numFields) {
4232: DMSetNumFields(dm, numFields);
4233: for (f = 0; f < numFields; ++f) {
4234: PetscObject disc;
4235: const char *name;
4237: PetscSectionGetFieldName(dm->localSection, f, &name);
4238: DMGetField(dm, f, NULL, &disc);
4239: PetscObjectSetName(disc, name);
4240: }
4241: }
4242: /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4243: PetscSectionDestroy(&dm->globalSection);
4244: return(0);
4245: }
4247: /*@
4248: DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
4250: not collective
4252: Input Parameter:
4253: . dm - The DM
4255: Output Parameter:
4256: + 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.
4257: - 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.
4259: Level: advanced
4261: Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
4263: .seealso: DMSetDefaultConstraints()
4264: @*/
4265: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4266: {
4271: if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4272: if (section) {*section = dm->defaultConstraintSection;}
4273: if (mat) {*mat = dm->defaultConstraintMat;}
4274: return(0);
4275: }
4277: /*@
4278: DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
4280: 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().
4282: 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.
4284: collective on dm
4286: Input Parameters:
4287: + dm - The DM
4288: + 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).
4289: - 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).
4291: Level: advanced
4293: Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
4295: .seealso: DMGetDefaultConstraints()
4296: @*/
4297: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4298: {
4299: PetscMPIInt result;
4304: if (section) {
4306: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4307: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4308: }
4309: if (mat) {
4311: MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4312: if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4313: }
4314: PetscObjectReference((PetscObject)section);
4315: PetscSectionDestroy(&dm->defaultConstraintSection);
4316: dm->defaultConstraintSection = section;
4317: PetscObjectReference((PetscObject)mat);
4318: MatDestroy(&dm->defaultConstraintMat);
4319: dm->defaultConstraintMat = mat;
4320: return(0);
4321: }
4323: #if defined(PETSC_USE_DEBUG)
4324: /*
4325: DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4327: Input Parameters:
4328: + dm - The DM
4329: . localSection - PetscSection describing the local data layout
4330: - globalSection - PetscSection describing the global data layout
4332: Level: intermediate
4334: .seealso: DMGetSectionSF(), DMSetSectionSF()
4335: */
4336: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4337: {
4338: MPI_Comm comm;
4339: PetscLayout layout;
4340: const PetscInt *ranges;
4341: PetscInt pStart, pEnd, p, nroots;
4342: PetscMPIInt size, rank;
4343: PetscBool valid = PETSC_TRUE, gvalid;
4344: PetscErrorCode ierr;
4347: PetscObjectGetComm((PetscObject)dm,&comm);
4349: MPI_Comm_size(comm, &size);
4350: MPI_Comm_rank(comm, &rank);
4351: PetscSectionGetChart(globalSection, &pStart, &pEnd);
4352: PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4353: PetscLayoutCreate(comm, &layout);
4354: PetscLayoutSetBlockSize(layout, 1);
4355: PetscLayoutSetLocalSize(layout, nroots);
4356: PetscLayoutSetUp(layout);
4357: PetscLayoutGetRanges(layout, &ranges);
4358: for (p = pStart; p < pEnd; ++p) {
4359: PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4361: PetscSectionGetDof(localSection, p, &dof);
4362: PetscSectionGetOffset(localSection, p, &off);
4363: PetscSectionGetConstraintDof(localSection, p, &cdof);
4364: PetscSectionGetDof(globalSection, p, &gdof);
4365: PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4366: PetscSectionGetOffset(globalSection, p, &goff);
4367: if (!gdof) continue; /* Censored point */
4368: 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;}
4369: 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;}
4370: if (gdof < 0) {
4371: gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4372: for (d = 0; d < gsize; ++d) {
4373: PetscInt offset = -(goff+1) + d, r;
4375: PetscFindInt(offset,size+1,ranges,&r);
4376: if (r < 0) r = -(r+2);
4377: 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;}
4378: }
4379: }
4380: }
4381: PetscLayoutDestroy(&layout);
4382: PetscSynchronizedFlush(comm, NULL);
4383: MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4384: if (!gvalid) {
4385: DMView(dm, NULL);
4386: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4387: }
4388: return(0);
4389: }
4390: #endif
4392: /*@
4393: DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4395: Collective on dm
4397: Input Parameter:
4398: . dm - The DM
4400: Output Parameter:
4401: . section - The PetscSection
4403: Level: intermediate
4405: Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4407: .seealso: DMSetLocalSection(), DMGetLocalSection()
4408: @*/
4409: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4410: {
4416: if (!dm->globalSection) {
4417: PetscSection s;
4419: DMGetLocalSection(dm, &s);
4420: if (!s) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4421: if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4422: PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4423: PetscLayoutDestroy(&dm->map);
4424: PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4425: PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4426: }
4427: *section = dm->globalSection;
4428: return(0);
4429: }
4431: /*@
4432: DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4434: Input Parameters:
4435: + dm - The DM
4436: - section - The PetscSection, or NULL
4438: Level: intermediate
4440: Note: Any existing Section will be destroyed
4442: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4443: @*/
4444: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4445: {
4451: PetscObjectReference((PetscObject)section);
4452: PetscSectionDestroy(&dm->globalSection);
4453: dm->globalSection = section;
4454: #if defined(PETSC_USE_DEBUG)
4455: if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4456: #endif
4457: return(0);
4458: }
4460: /*@
4461: DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4462: it is created from the default PetscSection layouts in the DM.
4464: Input Parameter:
4465: . dm - The DM
4467: Output Parameter:
4468: . sf - The PetscSF
4470: Level: intermediate
4472: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4474: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4475: @*/
4476: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4477: {
4478: PetscInt nroots;
4484: if (!dm->sectionSF) {
4485: PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4486: }
4487: PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4488: if (nroots < 0) {
4489: PetscSection section, gSection;
4491: DMGetLocalSection(dm, §ion);
4492: if (section) {
4493: DMGetGlobalSection(dm, &gSection);
4494: DMCreateSectionSF(dm, section, gSection);
4495: } else {
4496: *sf = NULL;
4497: return(0);
4498: }
4499: }
4500: *sf = dm->sectionSF;
4501: return(0);
4502: }
4504: /*@
4505: DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4507: Input Parameters:
4508: + dm - The DM
4509: - sf - The PetscSF
4511: Level: intermediate
4513: Note: Any previous SF is destroyed
4515: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4516: @*/
4517: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4518: {
4524: PetscObjectReference((PetscObject) sf);
4525: PetscSFDestroy(&dm->sectionSF);
4526: dm->sectionSF = sf;
4527: return(0);
4528: }
4530: /*@C
4531: DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4532: describing the data layout.
4534: Input Parameters:
4535: + dm - The DM
4536: . localSection - PetscSection describing the local data layout
4537: - globalSection - PetscSection describing the global data layout
4539: Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4541: Level: developer
4543: Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4544: directly into the DM, perhaps this function should not take the local and global sections as
4545: input and should just obtain them from the DM?
4547: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4548: @*/
4549: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4550: {
4555: PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4556: return(0);
4557: }
4559: /*@
4560: DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4562: Input Parameter:
4563: . dm - The DM
4565: Output Parameter:
4566: . sf - The PetscSF
4568: Level: intermediate
4570: Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4572: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4573: @*/
4574: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4575: {
4579: *sf = dm->sf;
4580: return(0);
4581: }
4583: /*@
4584: DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4586: Input Parameters:
4587: + dm - The DM
4588: - sf - The PetscSF
4590: Level: intermediate
4592: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4593: @*/
4594: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4595: {
4601: PetscObjectReference((PetscObject) sf);
4602: PetscSFDestroy(&dm->sf);
4603: dm->sf = sf;
4604: return(0);
4605: }
4607: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4608: {
4609: PetscClassId id;
4613: PetscObjectGetClassId(disc, &id);
4614: if (id == PETSCFE_CLASSID) {
4615: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4616: } else if (id == PETSCFV_CLASSID) {
4617: DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4618: } else {
4619: DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4620: }
4621: return(0);
4622: }
4624: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4625: {
4626: RegionField *tmpr;
4627: PetscInt Nf = dm->Nf, f;
4631: if (Nf >= NfNew) return(0);
4632: PetscMalloc1(NfNew, &tmpr);
4633: for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4634: for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4635: PetscFree(dm->fields);
4636: dm->Nf = NfNew;
4637: dm->fields = tmpr;
4638: return(0);
4639: }
4641: /*@
4642: DMClearFields - Remove all fields from the DM
4644: Logically collective on dm
4646: Input Parameter:
4647: . dm - The DM
4649: Level: intermediate
4651: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4652: @*/
4653: PetscErrorCode DMClearFields(DM dm)
4654: {
4655: PetscInt f;
4660: for (f = 0; f < dm->Nf; ++f) {
4661: PetscObjectDestroy(&dm->fields[f].disc);
4662: DMLabelDestroy(&dm->fields[f].label);
4663: }
4664: PetscFree(dm->fields);
4665: dm->fields = NULL;
4666: dm->Nf = 0;
4667: return(0);
4668: }
4670: /*@
4671: DMGetNumFields - Get the number of fields in the DM
4673: Not collective
4675: Input Parameter:
4676: . dm - The DM
4678: Output Parameter:
4679: . Nf - The number of fields
4681: Level: intermediate
4683: .seealso: DMSetNumFields(), DMSetField()
4684: @*/
4685: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4686: {
4690: *numFields = dm->Nf;
4691: return(0);
4692: }
4694: /*@
4695: DMSetNumFields - Set the number of fields in the DM
4697: Logically collective on dm
4699: Input Parameters:
4700: + dm - The DM
4701: - Nf - The number of fields
4703: Level: intermediate
4705: .seealso: DMGetNumFields(), DMSetField()
4706: @*/
4707: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4708: {
4709: PetscInt Nf, f;
4714: DMGetNumFields(dm, &Nf);
4715: for (f = Nf; f < numFields; ++f) {
4716: PetscContainer obj;
4718: PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4719: DMAddField(dm, NULL, (PetscObject) obj);
4720: PetscContainerDestroy(&obj);
4721: }
4722: return(0);
4723: }
4725: /*@
4726: DMGetField - Return the discretization object for a given DM field
4728: Not collective
4730: Input Parameters:
4731: + dm - The DM
4732: - f - The field number
4734: Output Parameters:
4735: + label - The label indicating the support of the field, or NULL for the entire mesh
4736: - field - The discretization object
4738: Level: intermediate
4740: .seealso: DMAddField(), DMSetField()
4741: @*/
4742: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4743: {
4747: 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);
4748: if (label) *label = dm->fields[f].label;
4749: if (field) *field = dm->fields[f].disc;
4750: return(0);
4751: }
4753: /* Does not clear the DS */
4754: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4755: {
4759: DMFieldEnlarge_Static(dm, f+1);
4760: DMLabelDestroy(&dm->fields[f].label);
4761: PetscObjectDestroy(&dm->fields[f].disc);
4762: dm->fields[f].label = label;
4763: dm->fields[f].disc = field;
4764: PetscObjectReference((PetscObject) label);
4765: PetscObjectReference((PetscObject) field);
4766: return(0);
4767: }
4769: /*@
4770: DMSetField - Set the discretization object for a given DM field
4772: Logically collective on dm
4774: Input Parameters:
4775: + dm - The DM
4776: . f - The field number
4777: . label - The label indicating the support of the field, or NULL for the entire mesh
4778: - field - The discretization object
4780: Level: intermediate
4782: .seealso: DMAddField(), DMGetField()
4783: @*/
4784: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4785: {
4792: if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4793: DMSetField_Internal(dm, f, label, field);
4794: DMSetDefaultAdjacency_Private(dm, f, field);
4795: DMClearDS(dm);
4796: return(0);
4797: }
4799: /*@
4800: DMAddField - Add the discretization object for the given DM field
4802: Logically collective on dm
4804: Input Parameters:
4805: + dm - The DM
4806: . label - The label indicating the support of the field, or NULL for the entire mesh
4807: - field - The discretization object
4809: Level: intermediate
4811: .seealso: DMSetField(), DMGetField()
4812: @*/
4813: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4814: {
4815: PetscInt Nf = dm->Nf;
4822: DMFieldEnlarge_Static(dm, Nf+1);
4823: dm->fields[Nf].label = label;
4824: dm->fields[Nf].disc = field;
4825: PetscObjectReference((PetscObject) label);
4826: PetscObjectReference((PetscObject) field);
4827: DMSetDefaultAdjacency_Private(dm, Nf, field);
4828: DMClearDS(dm);
4829: return(0);
4830: }
4832: /*@
4833: DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4835: Logically collective on dm
4837: Input Parameters:
4838: + dm - The DM
4839: . f - The field index
4840: - avoidTensor - The flag to avoid defining the field on tensor cells
4842: Level: intermediate
4844: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4845: @*/
4846: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4847: {
4849: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4850: dm->fields[f].avoidTensor = avoidTensor;
4851: return(0);
4852: }
4854: /*@
4855: DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4857: Logically collective on dm
4859: Input Parameters:
4860: + dm - The DM
4861: - f - The field index
4863: Output Parameter:
4864: . avoidTensor - The flag to avoid defining the field on tensor cells
4866: Level: intermediate
4868: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4869: @*/
4870: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4871: {
4873: if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4874: *avoidTensor = dm->fields[f].avoidTensor;
4875: return(0);
4876: }
4878: /*@
4879: DMCopyFields - Copy the discretizations for the DM into another DM
4881: Collective on dm
4883: Input Parameter:
4884: . dm - The DM
4886: Output Parameter:
4887: . newdm - The DM
4889: Level: advanced
4891: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4892: @*/
4893: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4894: {
4895: PetscInt Nf, f;
4899: if (dm == newdm) return(0);
4900: DMGetNumFields(dm, &Nf);
4901: DMClearFields(newdm);
4902: for (f = 0; f < Nf; ++f) {
4903: DMLabel label;
4904: PetscObject field;
4905: PetscBool useCone, useClosure;
4907: DMGetField(dm, f, &label, &field);
4908: DMSetField(newdm, f, label, field);
4909: DMGetAdjacency(dm, f, &useCone, &useClosure);
4910: DMSetAdjacency(newdm, f, useCone, useClosure);
4911: }
4912: return(0);
4913: }
4915: /*@
4916: DMGetAdjacency - Returns the flags for determining variable influence
4918: Not collective
4920: Input Parameters:
4921: + dm - The DM object
4922: - f - The field number, or PETSC_DEFAULT for the default adjacency
4924: Output Parameter:
4925: + useCone - Flag for variable influence starting with the cone operation
4926: - useClosure - Flag for variable influence using transitive closure
4928: Notes:
4929: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4930: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4931: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4932: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4934: Level: developer
4936: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4937: @*/
4938: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4939: {
4944: if (f < 0) {
4945: if (useCone) *useCone = dm->adjacency[0];
4946: if (useClosure) *useClosure = dm->adjacency[1];
4947: } else {
4948: PetscInt Nf;
4951: DMGetNumFields(dm, &Nf);
4952: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4953: if (useCone) *useCone = dm->fields[f].adjacency[0];
4954: if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4955: }
4956: return(0);
4957: }
4959: /*@
4960: DMSetAdjacency - Set the flags for determining variable influence
4962: Not collective
4964: Input Parameters:
4965: + dm - The DM object
4966: . f - The field number
4967: . useCone - Flag for variable influence starting with the cone operation
4968: - useClosure - Flag for variable influence using transitive closure
4970: Notes:
4971: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4972: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
4973: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
4974: Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4976: Level: developer
4978: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4979: @*/
4980: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4981: {
4984: if (f < 0) {
4985: dm->adjacency[0] = useCone;
4986: dm->adjacency[1] = useClosure;
4987: } else {
4988: PetscInt Nf;
4991: DMGetNumFields(dm, &Nf);
4992: if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4993: dm->fields[f].adjacency[0] = useCone;
4994: dm->fields[f].adjacency[1] = useClosure;
4995: }
4996: return(0);
4997: }
4999: /*@
5000: DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5002: Not collective
5004: Input Parameters:
5005: . dm - The DM object
5007: Output Parameter:
5008: + useCone - Flag for variable influence starting with the cone operation
5009: - useClosure - Flag for variable influence using transitive closure
5011: Notes:
5012: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5013: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5014: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5016: Level: developer
5018: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5019: @*/
5020: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5021: {
5022: PetscInt Nf;
5029: DMGetNumFields(dm, &Nf);
5030: if (!Nf) {
5031: DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5032: } else {
5033: DMGetAdjacency(dm, 0, useCone, useClosure);
5034: }
5035: return(0);
5036: }
5038: /*@
5039: DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5041: Not collective
5043: Input Parameters:
5044: + dm - The DM object
5045: . useCone - Flag for variable influence starting with the cone operation
5046: - useClosure - Flag for variable influence using transitive closure
5048: Notes:
5049: $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5050: $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5051: $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5053: Level: developer
5055: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5056: @*/
5057: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5058: {
5059: PetscInt Nf;
5064: DMGetNumFields(dm, &Nf);
5065: if (!Nf) {
5066: DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5067: } else {
5068: DMSetAdjacency(dm, 0, useCone, useClosure);
5069: }
5070: return(0);
5071: }
5073: /* Complete labels that are being used for FEM BC */
5074: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5075: {
5076: DMLabel label;
5077: PetscObject obj;
5078: PetscClassId id;
5079: PetscInt Nbd, bd;
5080: PetscBool isFE = PETSC_FALSE;
5081: PetscBool duplicate = PETSC_FALSE;
5085: DMGetField(dm, field, NULL, &obj);
5086: PetscObjectGetClassId(obj, &id);
5087: if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5088: DMGetLabel(dm, labelname, &label);
5089: if (isFE && label) {
5090: /* Only want to modify label once */
5091: PetscDSGetNumBoundary(ds, &Nbd);
5092: for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5093: const char *lname;
5095: PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5096: PetscStrcmp(lname, labelname, &duplicate);
5097: if (duplicate) break;
5098: }
5099: if (!duplicate) {
5100: DM plex;
5102: DMConvert(dm, DMPLEX, &plex);
5103: if (plex) {DMPlexLabelComplete(plex, label);}
5104: DMDestroy(&plex);
5105: }
5106: }
5107: return(0);
5108: }
5110: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5111: {
5112: DMSpace *tmpd;
5113: PetscInt Nds = dm->Nds, s;
5117: if (Nds >= NdsNew) return(0);
5118: PetscMalloc1(NdsNew, &tmpd);
5119: for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5120: for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5121: PetscFree(dm->probs);
5122: dm->Nds = NdsNew;
5123: dm->probs = tmpd;
5124: return(0);
5125: }
5127: /*@
5128: DMGetNumDS - Get the number of discrete systems in the DM
5130: Not collective
5132: Input Parameter:
5133: . dm - The DM
5135: Output Parameter:
5136: . Nds - The number of PetscDS objects
5138: Level: intermediate
5140: .seealso: DMGetDS(), DMGetCellDS()
5141: @*/
5142: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5143: {
5147: *Nds = dm->Nds;
5148: return(0);
5149: }
5151: /*@
5152: DMClearDS - Remove all discrete systems from the DM
5154: Logically collective on dm
5156: Input Parameter:
5157: . dm - The DM
5159: Level: intermediate
5161: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5162: @*/
5163: PetscErrorCode DMClearDS(DM dm)
5164: {
5165: PetscInt s;
5170: for (s = 0; s < dm->Nds; ++s) {
5171: PetscDSDestroy(&dm->probs[s].ds);
5172: DMLabelDestroy(&dm->probs[s].label);
5173: ISDestroy(&dm->probs[s].fields);
5174: }
5175: PetscFree(dm->probs);
5176: dm->probs = NULL;
5177: dm->Nds = 0;
5178: return(0);
5179: }
5181: /*@
5182: DMGetDS - Get the default PetscDS
5184: Not collective
5186: Input Parameter:
5187: . dm - The DM
5189: Output Parameter:
5190: . prob - The default PetscDS
5192: Level: intermediate
5194: .seealso: DMGetCellDS(), DMGetRegionDS()
5195: @*/
5196: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5197: {
5203: if (dm->Nds <= 0) {
5204: PetscDS ds;
5206: PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5207: DMSetRegionDS(dm, NULL, NULL, ds);
5208: PetscDSDestroy(&ds);
5209: }
5210: *prob = dm->probs[0].ds;
5211: return(0);
5212: }
5214: /*@
5215: DMGetCellDS - Get the PetscDS defined on a given cell
5217: Not collective
5219: Input Parameters:
5220: + dm - The DM
5221: - point - Cell for the DS
5223: Output Parameter:
5224: . prob - The PetscDS defined on the given cell
5226: Level: developer
5228: .seealso: DMGetDS(), DMSetRegionDS()
5229: @*/
5230: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5231: {
5232: PetscDS probDef = NULL;
5233: PetscInt s;
5239: if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5240: *prob = NULL;
5241: for (s = 0; s < dm->Nds; ++s) {
5242: PetscInt val;
5244: if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5245: else {
5246: DMLabelGetValue(dm->probs[s].label, point, &val);
5247: if (val >= 0) {*prob = dm->probs[s].ds; break;}
5248: }
5249: }
5250: if (!*prob) *prob = probDef;
5251: return(0);
5252: }
5254: /*@
5255: DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5257: Not collective
5259: Input Parameters:
5260: + dm - The DM
5261: - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5263: Output Parameters:
5264: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5265: - prob - The PetscDS defined on the given region, or NULL
5267: Note: If the label is missing, this function returns an error
5269: Level: advanced
5271: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5272: @*/
5273: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5274: {
5275: PetscInt Nds = dm->Nds, s;
5282: for (s = 0; s < Nds; ++s) {
5283: if (dm->probs[s].label == label) {
5284: if (fields) *fields = dm->probs[s].fields;
5285: if (ds) *ds = dm->probs[s].ds;
5286: return(0);
5287: }
5288: }
5289: return(0);
5290: }
5292: /*@
5293: DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5295: Collective on dm
5297: Input Parameters:
5298: + dm - The DM
5299: . label - The DMLabel defining the mesh region, or NULL for the entire mesh
5300: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5301: - prob - The PetscDS defined on the given cell
5303: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5304: the fields argument is ignored.
5306: Level: advanced
5308: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5309: @*/
5310: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5311: {
5312: PetscInt Nds = dm->Nds, s;
5319: for (s = 0; s < Nds; ++s) {
5320: if (dm->probs[s].label == label) {
5321: PetscDSDestroy(&dm->probs[s].ds);
5322: dm->probs[s].ds = ds;
5323: return(0);
5324: }
5325: }
5326: DMDSEnlarge_Static(dm, Nds+1);
5327: PetscObjectReference((PetscObject) label);
5328: PetscObjectReference((PetscObject) fields);
5329: PetscObjectReference((PetscObject) ds);
5330: if (!label) {
5331: /* Put the NULL label at the front, so it is returned as the default */
5332: for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5333: Nds = 0;
5334: }
5335: dm->probs[Nds].label = label;
5336: dm->probs[Nds].fields = fields;
5337: dm->probs[Nds].ds = ds;
5338: return(0);
5339: }
5341: /*@
5342: DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5344: Not collective
5346: Input Parameters:
5347: + dm - The DM
5348: - num - The region number, in [0, Nds)
5350: Output Parameters:
5351: + label - The region label, or NULL
5352: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5353: - ds - The PetscDS defined on the given region, or NULL
5355: Level: advanced
5357: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5358: @*/
5359: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5360: {
5361: PetscInt Nds;
5366: DMGetNumDS(dm, &Nds);
5367: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5368: if (label) {
5370: *label = dm->probs[num].label;
5371: }
5372: if (fields) {
5374: *fields = dm->probs[num].fields;
5375: }
5376: if (ds) {
5378: *ds = dm->probs[num].ds;
5379: }
5380: return(0);
5381: }
5383: /*@
5384: DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5386: Not collective
5388: Input Parameters:
5389: + dm - The DM
5390: . num - The region number, in [0, Nds)
5391: . label - The region label, or NULL
5392: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5393: - ds - The PetscDS defined on the given region, or NULL to prevent setting
5395: Level: advanced
5397: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5398: @*/
5399: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5400: {
5401: PetscInt Nds;
5407: DMGetNumDS(dm, &Nds);
5408: if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5409: PetscObjectReference((PetscObject) label);
5410: DMLabelDestroy(&dm->probs[num].label);
5411: dm->probs[num].label = label;
5412: if (fields) {
5414: PetscObjectReference((PetscObject) fields);
5415: ISDestroy(&dm->probs[num].fields);
5416: dm->probs[num].fields = fields;
5417: }
5418: if (ds) {
5420: PetscObjectReference((PetscObject) ds);
5421: PetscDSDestroy(&dm->probs[num].ds);
5422: dm->probs[num].ds = ds;
5423: }
5424: return(0);
5425: }
5427: /*@
5428: DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5430: Not collective
5432: Input Parameters:
5433: + dm - The DM
5434: - ds - The PetscDS defined on the given region
5436: Output Parameter:
5437: . num - The region number, in [0, Nds), or -1 if not found
5439: Level: advanced
5441: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5442: @*/
5443: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5444: {
5445: PetscInt Nds, n;
5452: DMGetNumDS(dm, &Nds);
5453: for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5454: if (n >= Nds) *num = -1;
5455: else *num = n;
5456: return(0);
5457: }
5459: /*@
5460: DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5462: Collective on dm
5464: Input Parameter:
5465: . dm - The DM
5467: Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5469: Level: intermediate
5471: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5472: @*/
5473: PetscErrorCode DMCreateDS(DM dm)
5474: {
5475: MPI_Comm comm;
5476: PetscDS dsDef;
5477: DMLabel *labelSet;
5478: PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5479: PetscBool doSetup = PETSC_TRUE, flg;
5484: if (!dm->fields) return(0);
5485: PetscObjectGetComm((PetscObject) dm, &comm);
5486: DMGetCoordinateDim(dm, &dE);
5487: /* Determine how many regions we have */
5488: PetscMalloc1(Nf, &labelSet);
5489: Nl = 0;
5490: Ndef = 0;
5491: for (f = 0; f < Nf; ++f) {
5492: DMLabel label = dm->fields[f].label;
5493: PetscInt l;
5495: if (!label) {++Ndef; continue;}
5496: for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5497: if (l < Nl) continue;
5498: labelSet[Nl++] = label;
5499: }
5500: /* Create default DS if there are no labels to intersect with */
5501: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5502: if (!dsDef && Ndef && !Nl) {
5503: IS fields;
5504: PetscInt *fld, nf;
5506: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5507: if (nf) {
5508: PetscMalloc1(nf, &fld);
5509: for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5510: ISCreate(PETSC_COMM_SELF, &fields);
5511: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5512: ISSetType(fields, ISGENERAL);
5513: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5515: PetscDSCreate(comm, &dsDef);
5516: DMSetRegionDS(dm, NULL, fields, dsDef);
5517: PetscDSDestroy(&dsDef);
5518: ISDestroy(&fields);
5519: }
5520: }
5521: DMGetRegionDS(dm, NULL, NULL, &dsDef);
5522: if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5523: /* Intersect labels with default fields */
5524: if (Ndef && Nl) {
5525: DM plex;
5526: DMLabel cellLabel;
5527: IS fieldIS, allcellIS, defcellIS = NULL;
5528: PetscInt *fields;
5529: const PetscInt *cells;
5530: PetscInt depth, nf = 0, n, c;
5532: DMConvert(dm, DMPLEX, &plex);
5533: DMPlexGetDepth(plex, &depth);
5534: DMGetStratumIS(plex, "dim", depth, &allcellIS);
5535: if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5536: for (l = 0; l < Nl; ++l) {
5537: DMLabel label = labelSet[l];
5538: IS pointIS;
5540: ISDestroy(&defcellIS);
5541: DMLabelGetStratumIS(label, 1, &pointIS);
5542: ISDifference(allcellIS, pointIS, &defcellIS);
5543: ISDestroy(&pointIS);
5544: }
5545: ISDestroy(&allcellIS);
5547: DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5548: ISGetLocalSize(defcellIS, &n);
5549: ISGetIndices(defcellIS, &cells);
5550: for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5551: ISRestoreIndices(defcellIS, &cells);
5552: ISDestroy(&defcellIS);
5553: DMPlexLabelComplete(plex, cellLabel);
5555: PetscMalloc1(Ndef, &fields);
5556: for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5557: ISCreate(PETSC_COMM_SELF, &fieldIS);
5558: PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5559: ISSetType(fieldIS, ISGENERAL);
5560: ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);
5562: PetscDSCreate(comm, &dsDef);
5563: DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5564: DMLabelDestroy(&cellLabel);
5565: PetscDSSetCoordinateDimension(dsDef, dE);
5566: PetscDSDestroy(&dsDef);
5567: ISDestroy(&fieldIS);
5568: DMDestroy(&plex);
5569: }
5570: /* Create label DSes
5571: - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5572: */
5573: /* TODO Should check that labels are disjoint */
5574: for (l = 0; l < Nl; ++l) {
5575: DMLabel label = labelSet[l];
5576: PetscDS ds;
5577: IS fields;
5578: PetscInt *fld, nf;
5580: PetscDSCreate(comm, &ds);
5581: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5582: PetscMalloc1(nf, &fld);
5583: for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5584: ISCreate(PETSC_COMM_SELF, &fields);
5585: PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5586: ISSetType(fields, ISGENERAL);
5587: ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5588: DMSetRegionDS(dm, label, fields, ds);
5589: ISDestroy(&fields);
5590: PetscDSSetCoordinateDimension(ds, dE);
5591: {
5592: DMPolytopeType ct;
5593: PetscInt lStart, lEnd;
5594: PetscBool isHybridLocal = PETSC_FALSE, isHybrid;
5596: DMLabelGetBounds(label, &lStart, &lEnd);
5597: if (lStart >= 0) {
5598: DMPlexGetCellType(dm, lStart, &ct);
5599: switch (ct) {
5600: case DM_POLYTOPE_POINT_PRISM_TENSOR:
5601: case DM_POLYTOPE_SEG_PRISM_TENSOR:
5602: case DM_POLYTOPE_TRI_PRISM_TENSOR:
5603: case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5604: isHybridLocal = PETSC_TRUE;break;
5605: default: break;
5606: }
5607: }
5608: MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5609: PetscDSSetHybrid(ds, isHybrid);
5610: }
5611: PetscDSDestroy(&ds);
5612: }
5613: PetscFree(labelSet);
5614: /* Set fields in DSes */
5615: for (s = 0; s < dm->Nds; ++s) {
5616: PetscDS ds = dm->probs[s].ds;
5617: IS fields = dm->probs[s].fields;
5618: const PetscInt *fld;
5619: PetscInt nf;
5621: ISGetLocalSize(fields, &nf);
5622: ISGetIndices(fields, &fld);
5623: for (f = 0; f < nf; ++f) {
5624: PetscObject disc = dm->fields[fld[f]].disc;
5625: PetscBool isHybrid;
5626: PetscClassId id;
5628: PetscDSGetHybrid(ds, &isHybrid);
5629: /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5630: if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5631: PetscDSSetDiscretization(ds, f, disc);
5632: /* We allow people to have placeholder fields and construct the Section by hand */
5633: PetscObjectGetClassId(disc, &id);
5634: if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5635: }
5636: ISRestoreIndices(fields, &fld);
5637: }
5638: /* Allow k-jet tabulation */
5639: PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5640: if (flg) {
5641: for (s = 0; s < dm->Nds; ++s) {PetscDSSetJetDegree(dm->probs[s].ds, 0, k);}
5642: }
5643: /* Setup DSes */
5644: if (doSetup) {
5645: for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5646: }
5647: return(0);
5648: }
5650: /*@
5651: DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5653: Collective on DM
5655: Input Parameters:
5656: + dm - The DM
5657: - time - The time
5659: Output Parameters:
5660: + u - The vector will be filled with exact solution values, or NULL
5661: - u_t - The vector will be filled with the time derivative of exact solution values, or NULL
5663: Note: The user must call PetscDSSetExactSolution() beforehand
5665: Level: developer
5667: .seealso: PetscDSSetExactSolution()
5668: @*/
5669: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5670: {
5671: PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5672: void **ectxs;
5673: PetscInt Nf, Nds, s;
5674: PetscErrorCode ierr;
5680: DMGetNumFields(dm, &Nf);
5681: PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5682: DMGetNumDS(dm, &Nds);
5683: for (s = 0; s < Nds; ++s) {
5684: PetscDS ds;
5685: DMLabel label;
5686: IS fieldIS;
5687: const PetscInt *fields, id = 1;
5688: PetscInt dsNf, f;
5690: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5691: PetscDSGetNumFields(ds, &dsNf);
5692: ISGetIndices(fieldIS, &fields);
5693: PetscArrayzero(exacts, Nf);
5694: PetscArrayzero(ectxs, Nf);
5695: if (u) {
5696: for (f = 0; f < dsNf; ++f) {
5697: const PetscInt field = fields[f];
5698: PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5699: }
5700: ISRestoreIndices(fieldIS, &fields);
5701: if (label) {
5702: DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5703: } else {
5704: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5705: }
5706: }
5707: if (u_t) {
5708: PetscArrayzero(exacts, Nf);
5709: PetscArrayzero(ectxs, Nf);
5710: for (f = 0; f < dsNf; ++f) {
5711: const PetscInt field = fields[f];
5712: PetscDSGetExactSolutionTimeDerivative(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_t);
5717: } else {
5718: DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5719: }
5720: }
5721: }
5722: if (u) {
5723: PetscObjectSetName((PetscObject) u, "Exact Solution");
5724: PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5725: }
5726: if (u_t) {
5727: PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5728: PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5729: }
5730: PetscFree2(exacts, ectxs);
5731: return(0);
5732: }
5734: /*@
5735: DMCopyDS - Copy the discrete systems for the DM into another DM
5737: Collective on dm
5739: Input Parameter:
5740: . dm - The DM
5742: Output Parameter:
5743: . newdm - The DM
5745: Level: advanced
5747: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5748: @*/
5749: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5750: {
5751: PetscInt Nds, s;
5755: if (dm == newdm) return(0);
5756: DMGetNumDS(dm, &Nds);
5757: DMClearDS(newdm);
5758: for (s = 0; s < Nds; ++s) {
5759: DMLabel label;
5760: IS fields;
5761: PetscDS ds;
5762: PetscInt Nbd, bd;
5764: DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5765: DMSetRegionDS(newdm, label, fields, ds);
5766: PetscDSGetNumBoundary(ds, &Nbd);
5767: for (bd = 0; bd < Nbd; ++bd) {
5768: const char *labelname, *name;
5769: PetscInt field;
5771: /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5772: PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5773: DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5774: }
5775: }
5776: return(0);
5777: }
5779: /*@
5780: DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5782: Collective on dm
5784: Input Parameter:
5785: . dm - The DM
5787: Output Parameter:
5788: . newdm - The DM
5790: Level: advanced
5792: .seealso: DMCopyFields(), DMCopyDS()
5793: @*/
5794: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5795: {
5799: DMCopyFields(dm, newdm);
5800: DMCopyDS(dm, newdm);
5801: return(0);
5802: }
5804: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5805: {
5806: DM dm_coord,dmc_coord;
5808: Vec coords,ccoords;
5809: Mat inject;
5811: DMGetCoordinateDM(dm,&dm_coord);
5812: DMGetCoordinateDM(dmc,&dmc_coord);
5813: DMGetCoordinates(dm,&coords);
5814: DMGetCoordinates(dmc,&ccoords);
5815: if (coords && !ccoords) {
5816: DMCreateGlobalVector(dmc_coord,&ccoords);
5817: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5818: DMCreateInjection(dmc_coord,dm_coord,&inject);
5819: MatRestrict(inject,coords,ccoords);
5820: MatDestroy(&inject);
5821: DMSetCoordinates(dmc,ccoords);
5822: VecDestroy(&ccoords);
5823: }
5824: return(0);
5825: }
5827: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5828: {
5829: DM dm_coord,subdm_coord;
5831: Vec coords,ccoords,clcoords;
5832: VecScatter *scat_i,*scat_g;
5834: DMGetCoordinateDM(dm,&dm_coord);
5835: DMGetCoordinateDM(subdm,&subdm_coord);
5836: DMGetCoordinates(dm,&coords);
5837: DMGetCoordinates(subdm,&ccoords);
5838: if (coords && !ccoords) {
5839: DMCreateGlobalVector(subdm_coord,&ccoords);
5840: PetscObjectSetName((PetscObject)ccoords,"coordinates");
5841: DMCreateLocalVector(subdm_coord,&clcoords);
5842: PetscObjectSetName((PetscObject)clcoords,"coordinates");
5843: DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5844: VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5845: VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5846: VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5847: VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5848: DMSetCoordinates(subdm,ccoords);
5849: DMSetCoordinatesLocal(subdm,clcoords);
5850: VecScatterDestroy(&scat_i[0]);
5851: VecScatterDestroy(&scat_g[0]);
5852: VecDestroy(&ccoords);
5853: VecDestroy(&clcoords);
5854: PetscFree(scat_i);
5855: PetscFree(scat_g);
5856: }
5857: return(0);
5858: }
5860: /*@
5861: DMGetDimension - Return the topological dimension of the DM
5863: Not collective
5865: Input Parameter:
5866: . dm - The DM
5868: Output Parameter:
5869: . dim - The topological dimension
5871: Level: beginner
5873: .seealso: DMSetDimension(), DMCreate()
5874: @*/
5875: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5876: {
5880: *dim = dm->dim;
5881: return(0);
5882: }
5884: /*@
5885: DMSetDimension - Set the topological dimension of the DM
5887: Collective on dm
5889: Input Parameters:
5890: + dm - The DM
5891: - dim - The topological dimension
5893: Level: beginner
5895: .seealso: DMGetDimension(), DMCreate()
5896: @*/
5897: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5898: {
5899: PetscDS ds;
5905: dm->dim = dim;
5906: DMGetDS(dm, &ds);
5907: if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5908: return(0);
5909: }
5911: /*@
5912: DMGetDimPoints - Get the half-open interval for all points of a given dimension
5914: Collective on dm
5916: Input Parameters:
5917: + dm - the DM
5918: - dim - the dimension
5920: Output Parameters:
5921: + pStart - The first point of the given dimension
5922: - pEnd - The first point following points of the given dimension
5924: Note:
5925: The points are vertices in the Hasse diagram encoding the topology. This is explained in
5926: https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5927: then the interval is empty.
5929: Level: intermediate
5931: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5932: @*/
5933: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5934: {
5935: PetscInt d;
5940: DMGetDimension(dm, &d);
5941: if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5942: if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5943: (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5944: return(0);
5945: }
5947: /*@
5948: DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5950: Collective on dm
5952: Input Parameters:
5953: + dm - the DM
5954: - c - coordinate vector
5956: Notes:
5957: The coordinates do include those for ghost points, which are in the local vector.
5959: The vector c should be destroyed by the caller.
5961: Level: intermediate
5963: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
5964: @*/
5965: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5966: {
5972: PetscObjectReference((PetscObject) c);
5973: VecDestroy(&dm->coordinates);
5974: dm->coordinates = c;
5975: VecDestroy(&dm->coordinatesLocal);
5976: DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5977: DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5978: return(0);
5979: }
5981: /*@
5982: DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5984: Not collective
5986: Input Parameters:
5987: + dm - the DM
5988: - c - coordinate vector
5990: Notes:
5991: The coordinates of ghost points can be set using DMSetCoordinates()
5992: followed by DMGetCoordinatesLocal(). This is intended to enable the
5993: setting of ghost coordinates outside of the domain.
5995: The vector c should be destroyed by the caller.
5997: Level: intermediate
5999: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6000: @*/
6001: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6002: {
6008: PetscObjectReference((PetscObject) c);
6009: VecDestroy(&dm->coordinatesLocal);
6011: dm->coordinatesLocal = c;
6013: VecDestroy(&dm->coordinates);
6014: return(0);
6015: }
6017: /*@
6018: DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
6020: Collective on dm
6022: Input Parameter:
6023: . dm - the DM
6025: Output Parameter:
6026: . c - global coordinate vector
6028: Note:
6029: This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6030: destroyed the array will no longer be valid.
6032: Each process has only the local coordinates (does NOT have the ghost coordinates).
6034: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6035: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6037: Level: intermediate
6039: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6040: @*/
6041: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6042: {
6048: if (!dm->coordinates && dm->coordinatesLocal) {
6049: DM cdm = NULL;
6050: PetscBool localized;
6052: DMGetCoordinateDM(dm, &cdm);
6053: DMCreateGlobalVector(cdm, &dm->coordinates);
6054: DMGetCoordinatesLocalized(dm, &localized);
6055: /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6056: if (localized) {
6057: PetscInt cdim;
6059: DMGetCoordinateDim(dm, &cdim);
6060: VecSetBlockSize(dm->coordinates, cdim);
6061: }
6062: PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6063: DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6064: DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6065: }
6066: *c = dm->coordinates;
6067: return(0);
6068: }
6070: /*@
6071: DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6073: Collective on dm
6075: Input Parameter:
6076: . dm - the DM
6078: Level: advanced
6080: .seealso: DMGetCoordinatesLocalNoncollective()
6081: @*/
6082: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6083: {
6088: if (!dm->coordinatesLocal && dm->coordinates) {
6089: DM cdm = NULL;
6090: PetscBool localized;
6092: DMGetCoordinateDM(dm, &cdm);
6093: DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6094: DMGetCoordinatesLocalized(dm, &localized);
6095: /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6096: if (localized) {
6097: PetscInt cdim;
6099: DMGetCoordinateDim(dm, &cdim);
6100: VecSetBlockSize(dm->coordinates, cdim);
6101: }
6102: PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6103: DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6104: DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6105: }
6106: return(0);
6107: }
6109: /*@
6110: DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6112: Collective on dm
6114: Input Parameter:
6115: . dm - the DM
6117: Output Parameter:
6118: . c - coordinate vector
6120: Note:
6121: This is a borrowed reference, so the user should NOT destroy this vector
6123: Each process has the local and ghost coordinates
6125: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6126: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6128: Level: intermediate
6130: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6131: @*/
6132: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6133: {
6139: DMGetCoordinatesLocalSetUp(dm);
6140: *c = dm->coordinatesLocal;
6141: return(0);
6142: }
6144: /*@
6145: DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6147: Not collective
6149: Input Parameter:
6150: . dm - the DM
6152: Output Parameter:
6153: . c - coordinate vector
6155: Level: advanced
6157: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6158: @*/
6159: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6160: {
6164: if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6165: *c = dm->coordinatesLocal;
6166: return(0);
6167: }
6169: /*@
6170: DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6172: Not collective
6174: Input Parameter:
6175: + dm - the DM
6176: - p - the IS of points whose coordinates will be returned
6178: Output Parameter:
6179: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6180: - pCoord - the Vec with coordinates of points in p
6182: Note:
6183: DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6185: This creates a new vector, so the user SHOULD destroy this vector
6187: Each process has the local and ghost coordinates
6189: For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6190: and (x_0,y_0,z_0,x_1,y_1,z_1...)
6192: Level: advanced
6194: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6195: @*/
6196: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6197: {
6198: PetscSection cs, newcs;
6199: Vec coords;
6200: const PetscScalar *arr;
6201: PetscScalar *newarr=NULL;
6202: PetscInt n;
6203: PetscErrorCode ierr;
6210: if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6211: if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6212: cs = dm->coordinateDM->localSection;
6213: coords = dm->coordinatesLocal;
6214: VecGetArrayRead(coords, &arr);
6215: PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6216: VecRestoreArrayRead(coords, &arr);
6217: if (pCoord) {
6218: PetscSectionGetStorageSize(newcs, &n);
6219: /* set array in two steps to mimic PETSC_OWN_POINTER */
6220: VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6221: VecReplaceArray(*pCoord, newarr);
6222: } else {
6223: PetscFree(newarr);
6224: }
6225: if (pCoordSection) {*pCoordSection = newcs;}
6226: else {PetscSectionDestroy(&newcs);}
6227: return(0);
6228: }
6230: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6231: {
6237: if (!dm->coordinateField) {
6238: if (dm->ops->createcoordinatefield) {
6239: (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6240: }
6241: }
6242: *field = dm->coordinateField;
6243: return(0);
6244: }
6246: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6247: {
6253: PetscObjectReference((PetscObject)field);
6254: DMFieldDestroy(&dm->coordinateField);
6255: dm->coordinateField = field;
6256: return(0);
6257: }
6259: /*@
6260: DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6262: Collective on dm
6264: Input Parameter:
6265: . dm - the DM
6267: Output Parameter:
6268: . cdm - coordinate DM
6270: Level: intermediate
6272: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6273: @*/
6274: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6275: {
6281: if (!dm->coordinateDM) {
6282: DM cdm;
6284: if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6285: (*dm->ops->createcoordinatedm)(dm, &cdm);
6286: /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6287: * until the call to CreateCoordinateDM) */
6288: DMDestroy(&dm->coordinateDM);
6289: dm->coordinateDM = cdm;
6290: }
6291: *cdm = dm->coordinateDM;
6292: return(0);
6293: }
6295: /*@
6296: DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6298: Logically Collective on dm
6300: Input Parameters:
6301: + dm - the DM
6302: - cdm - coordinate DM
6304: Level: intermediate
6306: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6307: @*/
6308: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6309: {
6315: PetscObjectReference((PetscObject)cdm);
6316: DMDestroy(&dm->coordinateDM);
6317: dm->coordinateDM = cdm;
6318: return(0);
6319: }
6321: /*@
6322: DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6324: Not Collective
6326: Input Parameter:
6327: . dm - The DM object
6329: Output Parameter:
6330: . dim - The embedding dimension
6332: Level: intermediate
6334: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6335: @*/
6336: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6337: {
6341: if (dm->dimEmbed == PETSC_DEFAULT) {
6342: dm->dimEmbed = dm->dim;
6343: }
6344: *dim = dm->dimEmbed;
6345: return(0);
6346: }
6348: /*@
6349: DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6351: Not Collective
6353: Input Parameters:
6354: + dm - The DM object
6355: - dim - The embedding dimension
6357: Level: intermediate
6359: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6360: @*/
6361: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6362: {
6363: PetscDS ds;
6368: dm->dimEmbed = dim;
6369: DMGetDS(dm, &ds);
6370: PetscDSSetCoordinateDimension(ds, dim);
6371: return(0);
6372: }
6374: /*@
6375: DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6377: Collective on dm
6379: Input Parameter:
6380: . dm - The DM object
6382: Output Parameter:
6383: . section - The PetscSection object
6385: Level: intermediate
6387: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6388: @*/
6389: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6390: {
6391: DM cdm;
6397: DMGetCoordinateDM(dm, &cdm);
6398: DMGetLocalSection(cdm, section);
6399: return(0);
6400: }
6402: /*@
6403: DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6405: Not Collective
6407: Input Parameters:
6408: + dm - The DM object
6409: . dim - The embedding dimension, or PETSC_DETERMINE
6410: - section - The PetscSection object
6412: Level: intermediate
6414: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6415: @*/
6416: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6417: {
6418: DM cdm;
6424: DMGetCoordinateDM(dm, &cdm);
6425: DMSetLocalSection(cdm, section);
6426: if (dim == PETSC_DETERMINE) {
6427: PetscInt d = PETSC_DEFAULT;
6428: PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6430: PetscSectionGetChart(section, &pStart, &pEnd);
6431: DMGetDimPoints(dm, 0, &vStart, &vEnd);
6432: pStart = PetscMax(vStart, pStart);
6433: pEnd = PetscMin(vEnd, pEnd);
6434: for (v = pStart; v < pEnd; ++v) {
6435: PetscSectionGetDof(section, v, &dd);
6436: if (dd) {d = dd; break;}
6437: }
6438: if (d >= 0) {DMSetCoordinateDim(dm, d);}
6439: }
6440: return(0);
6441: }
6443: /*@
6444: DMProjectCoordinates - Project coordinates to a different space
6446: Input Parameters:
6447: + dm - The DM object
6448: - disc - The new coordinate discretization
6450: Level: intermediate
6452: .seealso: DMGetCoordinateField()
6453: @*/
6454: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6455: {
6456: PetscObject discOld;
6457: PetscClassId classid;
6458: DM cdmOld,cdmNew;
6459: Vec coordsOld,coordsNew;
6460: Mat matInterp;
6467: DMGetCoordinateDM(dm, &cdmOld);
6468: /* Check current discretization is compatible */
6469: DMGetField(cdmOld, 0, NULL, &discOld);
6470: PetscObjectGetClassId(discOld, &classid);
6471: if (classid != PETSCFE_CLASSID) {
6472: if (classid == PETSC_CONTAINER_CLASSID) {
6473: PetscFE feLinear;
6474: DMPolytopeType ct;
6475: PetscInt dim, dE, cStart;
6476: PetscBool simplex;
6478: /* Assume linear vertex coordinates */
6479: DMGetDimension(dm, &dim);
6480: DMGetCoordinateDim(dm, &dE);
6481: DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6482: DMPlexGetCellType(dm, cStart, &ct);
6483: switch (ct) {
6484: case DM_POLYTOPE_TRI_PRISM:
6485: case DM_POLYTOPE_TRI_PRISM_TENSOR:
6486: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6487: default: break;
6488: }
6489: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6490: PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6491: DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6492: PetscFEDestroy(&feLinear);
6493: DMCreateDS(cdmOld);
6494: } else {
6495: const char *discname;
6497: PetscObjectGetType(discOld, &discname);
6498: SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6499: }
6500: }
6501: /* Make a fresh clone of the coordinate DM */
6502: DMClone(cdmOld, &cdmNew);
6503: DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6504: DMCreateDS(cdmNew);
6505: /* Project the coordinate vector from old to new space */
6506: DMGetCoordinates(dm, &coordsOld);
6507: DMCreateGlobalVector(cdmNew, &coordsNew);
6508: DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6509: MatInterpolate(matInterp, coordsOld, coordsNew);
6510: MatDestroy(&matInterp);
6511: /* Set new coordinate structures */
6512: DMSetCoordinateField(dm, NULL);
6513: DMSetCoordinateDM(dm, cdmNew);
6514: DMSetCoordinates(dm, coordsNew);
6515: VecDestroy(&coordsNew);
6516: DMDestroy(&cdmNew);
6517: return(0);
6518: }
6520: /*@C
6521: DMGetPeriodicity - Get the description of mesh periodicity
6523: Input Parameters:
6524: . dm - The DM object
6526: Output Parameters:
6527: + per - Whether the DM is periodic or not
6528: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6529: . L - If we assume the mesh is a torus, this is the length of each coordinate
6530: - bd - This describes the type of periodicity in each topological dimension
6532: Level: developer
6534: .seealso: DMGetPeriodicity()
6535: @*/
6536: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6537: {
6540: if (per) *per = dm->periodic;
6541: if (L) *L = dm->L;
6542: if (maxCell) *maxCell = dm->maxCell;
6543: if (bd) *bd = dm->bdtype;
6544: return(0);
6545: }
6547: /*@C
6548: DMSetPeriodicity - Set the description of mesh periodicity
6550: Input Parameters:
6551: + dm - The DM object
6552: . per - Whether the DM is periodic or not.
6553: . 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.
6554: . L - If we assume the mesh is a torus, this is the length of each coordinate
6555: - bd - This describes the type of periodicity in each topological dimension
6557: 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.
6559: Level: developer
6561: .seealso: DMGetPeriodicity()
6562: @*/
6563: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6564: {
6565: PetscInt dim, d;
6574: DMGetDimension(dm, &dim);
6575: if (maxCell) {
6576: if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6577: for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6578: } else { /* remove maxCell information to disable automatic computation of localized vertices */
6579: PetscFree(dm->maxCell);
6580: }
6582: if (L) {
6583: if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6584: for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6585: }
6586: if (bd) {
6587: if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6588: for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6589: }
6590: dm->periodic = per;
6591: return(0);
6592: }
6594: /*@
6595: 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.
6597: Input Parameters:
6598: + dm - The DM
6599: . in - The input coordinate point (dim numbers)
6600: - endpoint - Include the endpoint L_i
6602: Output Parameter:
6603: . out - The localized coordinate point
6605: Level: developer
6607: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6608: @*/
6609: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6610: {
6611: PetscInt dim, d;
6615: DMGetCoordinateDim(dm, &dim);
6616: if (!dm->maxCell) {
6617: for (d = 0; d < dim; ++d) out[d] = in[d];
6618: } else {
6619: if (endpoint) {
6620: for (d = 0; d < dim; ++d) {
6621: 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)) {
6622: out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6623: } else {
6624: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6625: }
6626: }
6627: } else {
6628: for (d = 0; d < dim; ++d) {
6629: out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6630: }
6631: }
6632: }
6633: return(0);
6634: }
6636: /*
6637: 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.
6639: Input Parameters:
6640: + dm - The DM
6641: . dim - The spatial dimension
6642: . anchor - The anchor point, the input point can be no more than maxCell away from it
6643: - in - The input coordinate point (dim numbers)
6645: Output Parameter:
6646: . out - The localized coordinate point
6648: Level: developer
6650: 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
6652: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6653: */
6654: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6655: {
6656: PetscInt d;
6659: if (!dm->maxCell) {
6660: for (d = 0; d < dim; ++d) out[d] = in[d];
6661: } else {
6662: for (d = 0; d < dim; ++d) {
6663: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6664: out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6665: } else {
6666: out[d] = in[d];
6667: }
6668: }
6669: }
6670: return(0);
6671: }
6673: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6674: {
6675: PetscInt d;
6678: if (!dm->maxCell) {
6679: for (d = 0; d < dim; ++d) out[d] = in[d];
6680: } else {
6681: for (d = 0; d < dim; ++d) {
6682: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6683: out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6684: } else {
6685: out[d] = in[d];
6686: }
6687: }
6688: }
6689: return(0);
6690: }
6692: /*
6693: 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.
6695: Input Parameters:
6696: + dm - The DM
6697: . dim - The spatial dimension
6698: . anchor - The anchor point, the input point can be no more than maxCell away from it
6699: . in - The input coordinate delta (dim numbers)
6700: - out - The input coordinate point (dim numbers)
6702: Output Parameter:
6703: . out - The localized coordinate in + out
6705: Level: developer
6707: 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
6709: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6710: */
6711: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6712: {
6713: PetscInt d;
6716: if (!dm->maxCell) {
6717: for (d = 0; d < dim; ++d) out[d] += in[d];
6718: } else {
6719: for (d = 0; d < dim; ++d) {
6720: const PetscReal maxC = dm->maxCell[d];
6722: if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6723: const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6725: if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6726: 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]));
6727: out[d] += newCoord;
6728: } else {
6729: out[d] += in[d];
6730: }
6731: }
6732: }
6733: return(0);
6734: }
6736: /*@
6737: DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6739: Not collective
6741: Input Parameter:
6742: . dm - The DM
6744: Output Parameter:
6745: areLocalized - True if localized
6747: Level: developer
6749: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6750: @*/
6751: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6752: {
6753: DM cdm;
6754: PetscSection coordSection;
6755: PetscInt cStart, cEnd, sStart, sEnd, c, dof;
6756: PetscBool isPlex, alreadyLocalized;
6762: *areLocalized = PETSC_FALSE;
6764: /* We need some generic way of refering to cells/vertices */
6765: DMGetCoordinateDM(dm, &cdm);
6766: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6767: if (!isPlex) return(0);
6769: DMGetCoordinateSection(dm, &coordSection);
6770: DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6771: PetscSectionGetChart(coordSection, &sStart, &sEnd);
6772: alreadyLocalized = PETSC_FALSE;
6773: for (c = cStart; c < cEnd; ++c) {
6774: if (c < sStart || c >= sEnd) continue;
6775: PetscSectionGetDof(coordSection, c, &dof);
6776: if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6777: }
6778: *areLocalized = alreadyLocalized;
6779: return(0);
6780: }
6782: /*@
6783: DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6785: Collective on dm
6787: Input Parameter:
6788: . dm - The DM
6790: Output Parameter:
6791: areLocalized - True if localized
6793: Level: developer
6795: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6796: @*/
6797: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6798: {
6799: PetscBool localized;
6805: DMGetCoordinatesLocalizedLocal(dm,&localized);
6806: MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6807: return(0);
6808: }
6810: /*@
6811: DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6813: Collective on dm
6815: Input Parameter:
6816: . dm - The DM
6818: Level: developer
6820: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6821: @*/
6822: PetscErrorCode DMLocalizeCoordinates(DM dm)
6823: {
6824: DM cdm;
6825: PetscSection coordSection, cSection;
6826: Vec coordinates, cVec;
6827: PetscScalar *coords, *coords2, *anchor, *localized;
6828: PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6829: PetscBool alreadyLocalized, alreadyLocalizedGlobal;
6830: PetscInt maxHeight = 0, h;
6831: PetscInt *pStart = NULL, *pEnd = NULL;
6836: if (!dm->periodic) return(0);
6837: DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6838: if (alreadyLocalized) return(0);
6840: /* We need some generic way of refering to cells/vertices */
6841: DMGetCoordinateDM(dm, &cdm);
6842: {
6843: PetscBool isplex;
6845: PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6846: if (isplex) {
6847: DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6848: DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6849: DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6850: pEnd = &pStart[maxHeight + 1];
6851: newStart = vStart;
6852: newEnd = vEnd;
6853: for (h = 0; h <= maxHeight; h++) {
6854: DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6855: newStart = PetscMin(newStart,pStart[h]);
6856: newEnd = PetscMax(newEnd,pEnd[h]);
6857: }
6858: } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6859: }
6860: DMGetCoordinatesLocal(dm, &coordinates);
6861: if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6862: DMGetCoordinateSection(dm, &coordSection);
6863: VecGetBlockSize(coordinates, &bs);
6864: PetscSectionGetChart(coordSection,&sStart,&sEnd);
6866: PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6867: PetscSectionSetNumFields(cSection, 1);
6868: PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6869: PetscSectionSetFieldComponents(cSection, 0, Nc);
6870: PetscSectionSetChart(cSection, newStart, newEnd);
6872: DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6873: localized = &anchor[bs];
6874: alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6875: for (h = 0; h <= maxHeight; h++) {
6876: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6878: for (c = cStart; c < cEnd; ++c) {
6879: PetscScalar *cellCoords = NULL;
6880: PetscInt b;
6882: if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6883: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6884: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6885: for (d = 0; d < dof/bs; ++d) {
6886: DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6887: for (b = 0; b < bs; b++) {
6888: if (cellCoords[d*bs + b] != localized[b]) break;
6889: }
6890: if (b < bs) break;
6891: }
6892: if (d < dof/bs) {
6893: if (c >= sStart && c < sEnd) {
6894: PetscInt cdof;
6896: PetscSectionGetDof(coordSection, c, &cdof);
6897: if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6898: }
6899: PetscSectionSetDof(cSection, c, dof);
6900: PetscSectionSetFieldDof(cSection, c, 0, dof);
6901: }
6902: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6903: }
6904: }
6905: MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6906: if (alreadyLocalizedGlobal) {
6907: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6908: PetscSectionDestroy(&cSection);
6909: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6910: return(0);
6911: }
6912: for (v = vStart; v < vEnd; ++v) {
6913: PetscSectionGetDof(coordSection, v, &dof);
6914: PetscSectionSetDof(cSection, v, dof);
6915: PetscSectionSetFieldDof(cSection, v, 0, dof);
6916: }
6917: PetscSectionSetUp(cSection);
6918: PetscSectionGetStorageSize(cSection, &coordSize);
6919: VecCreate(PETSC_COMM_SELF, &cVec);
6920: PetscObjectSetName((PetscObject)cVec,"coordinates");
6921: VecSetBlockSize(cVec, bs);
6922: VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6923: VecSetType(cVec, VECSTANDARD);
6924: VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6925: VecGetArray(cVec, &coords2);
6926: for (v = vStart; v < vEnd; ++v) {
6927: PetscSectionGetDof(coordSection, v, &dof);
6928: PetscSectionGetOffset(coordSection, v, &off);
6929: PetscSectionGetOffset(cSection, v, &off2);
6930: for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6931: }
6932: for (h = 0; h <= maxHeight; h++) {
6933: PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6935: for (c = cStart; c < cEnd; ++c) {
6936: PetscScalar *cellCoords = NULL;
6937: PetscInt b, cdof;
6939: PetscSectionGetDof(cSection,c,&cdof);
6940: if (!cdof) continue;
6941: DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6942: PetscSectionGetOffset(cSection, c, &off2);
6943: for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6944: for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6945: DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6946: }
6947: }
6948: DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6949: DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6950: VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6951: VecRestoreArray(cVec, &coords2);
6952: DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6953: DMSetCoordinatesLocal(dm, cVec);
6954: VecDestroy(&cVec);
6955: PetscSectionDestroy(&cSection);
6956: return(0);
6957: }
6959: /*@
6960: DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6962: Collective on v (see explanation below)
6964: Input Parameters:
6965: + dm - The DM
6966: . v - The Vec of points
6967: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6968: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6970: Output Parameter:
6971: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6972: - cells - The PetscSF containing the ranks and local indices of the containing points.
6975: Level: developer
6977: Notes:
6978: To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6979: To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6981: If *cellSF is NULL on input, a PetscSF will be created.
6982: If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6984: An array that maps each point to its containing cell can be obtained with
6986: $ const PetscSFNode *cells;
6987: $ PetscInt nFound;
6988: $ const PetscInt *found;
6989: $
6990: $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6992: Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6993: the index of the cell in its rank's local numbering.
6995: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6996: @*/
6997: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6998: {
7005: if (*cellSF) {
7006: PetscMPIInt result;
7009: MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7010: if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7011: } else {
7012: PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7013: }
7014: if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7015: PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7016: (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7017: PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7018: return(0);
7019: }
7021: /*@
7022: DMGetOutputDM - Retrieve the DM associated with the layout for output
7024: Collective on dm
7026: Input Parameter:
7027: . dm - The original DM
7029: Output Parameter:
7030: . odm - The DM which provides the layout for output
7032: Level: intermediate
7034: .seealso: VecView(), DMGetGlobalSection()
7035: @*/
7036: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7037: {
7038: PetscSection section;
7039: PetscBool hasConstraints, ghasConstraints;
7045: DMGetLocalSection(dm, §ion);
7046: PetscSectionHasConstraints(section, &hasConstraints);
7047: MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7048: if (!ghasConstraints) {
7049: *odm = dm;
7050: return(0);
7051: }
7052: if (!dm->dmBC) {
7053: PetscSection newSection, gsection;
7054: PetscSF sf;
7056: DMClone(dm, &dm->dmBC);
7057: DMCopyDisc(dm, dm->dmBC);
7058: PetscSectionClone(section, &newSection);
7059: DMSetLocalSection(dm->dmBC, newSection);
7060: PetscSectionDestroy(&newSection);
7061: DMGetPointSF(dm->dmBC, &sf);
7062: PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7063: DMSetGlobalSection(dm->dmBC, gsection);
7064: PetscSectionDestroy(&gsection);
7065: }
7066: *odm = dm->dmBC;
7067: return(0);
7068: }
7070: /*@
7071: DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7073: Input Parameter:
7074: . dm - The original DM
7076: Output Parameters:
7077: + num - The output sequence number
7078: - val - The output sequence value
7080: Level: intermediate
7082: Note: This is intended for output that should appear in sequence, for instance
7083: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7085: .seealso: VecView()
7086: @*/
7087: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7088: {
7093: return(0);
7094: }
7096: /*@
7097: DMSetOutputSequenceNumber - Set the sequence number/value for output
7099: Input Parameters:
7100: + dm - The original DM
7101: . num - The output sequence number
7102: - val - The output sequence value
7104: Level: intermediate
7106: Note: This is intended for output that should appear in sequence, for instance
7107: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7109: .seealso: VecView()
7110: @*/
7111: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7112: {
7115: dm->outputSequenceNum = num;
7116: dm->outputSequenceVal = val;
7117: return(0);
7118: }
7120: /*@C
7121: DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7123: Input Parameters:
7124: + dm - The original DM
7125: . name - The sequence name
7126: - num - The output sequence number
7128: Output Parameter:
7129: . val - The output sequence value
7131: Level: intermediate
7133: Note: This is intended for output that should appear in sequence, for instance
7134: a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7136: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7137: @*/
7138: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7139: {
7140: PetscBool ishdf5;
7147: PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7148: if (ishdf5) {
7149: #if defined(PETSC_HAVE_HDF5)
7150: PetscScalar value;
7152: DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7153: *val = PetscRealPart(value);
7154: #endif
7155: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7156: return(0);
7157: }
7159: /*@
7160: DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7162: Not collective
7164: Input Parameter:
7165: . dm - The DM
7167: Output Parameter:
7168: . useNatural - The flag to build the mapping to a natural order during distribution
7170: Level: beginner
7172: .seealso: DMSetUseNatural(), DMCreate()
7173: @*/
7174: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7175: {
7179: *useNatural = dm->useNatural;
7180: return(0);
7181: }
7183: /*@
7184: DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7186: Collective on dm
7188: Input Parameters:
7189: + dm - The DM
7190: - useNatural - The flag to build the mapping to a natural order during distribution
7192: Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7194: Level: beginner
7196: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7197: @*/
7198: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7199: {
7203: dm->useNatural = useNatural;
7204: return(0);
7205: }
7208: /*@C
7209: DMCreateLabel - Create a label of the given name if it does not already exist
7211: Not Collective
7213: Input Parameters:
7214: + dm - The DM object
7215: - name - The label name
7217: Level: intermediate
7219: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7220: @*/
7221: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7222: {
7223: PetscBool flg;
7224: DMLabel label;
7230: DMHasLabel(dm, name, &flg);
7231: if (!flg) {
7232: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7233: DMAddLabel(dm, label);
7234: DMLabelDestroy(&label);
7235: }
7236: return(0);
7237: }
7239: /*@C
7240: DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.
7242: Not Collective
7244: Input Parameters:
7245: + dm - The DM object
7246: . l - The index for the label
7247: - name - The label name
7249: Level: intermediate
7251: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7252: @*/
7253: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7254: {
7255: DMLabelLink orig, prev = NULL;
7256: DMLabel label;
7257: PetscInt Nl, m;
7258: PetscBool flg, match;
7259: const char *lname;
7265: DMHasLabel(dm, name, &flg);
7266: if (!flg) {
7267: DMLabelCreate(PETSC_COMM_SELF, name, &label);
7268: DMAddLabel(dm, label);
7269: DMLabelDestroy(&label);
7270: }
7271: DMGetNumLabels(dm, &Nl);
7272: if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7273: for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7274: PetscObjectGetName((PetscObject) orig->label, &lname);
7275: PetscStrcmp(name, lname, &match);
7276: if (match) break;
7277: }
7278: if (m == l) return(0);
7279: if (!m) dm->labels = orig->next;
7280: else prev->next = orig->next;
7281: if (!l) {
7282: orig->next = dm->labels;
7283: dm->labels = orig;
7284: } else {
7285: for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7286: orig->next = prev->next;
7287: prev->next = orig;
7288: }
7289: return(0);
7290: }
7292: /*@C
7293: DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7295: Not Collective
7297: Input Parameters:
7298: + dm - The DM object
7299: . name - The label name
7300: - point - The mesh point
7302: Output Parameter:
7303: . value - The label value for this point, or -1 if the point is not in the label
7305: Level: beginner
7307: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7308: @*/
7309: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7310: {
7311: DMLabel label;
7317: DMGetLabel(dm, name, &label);
7318: if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7319: DMLabelGetValue(label, point, value);
7320: return(0);
7321: }
7323: /*@C
7324: DMSetLabelValue - Add a point to a Sieve Label with given value
7326: Not Collective
7328: Input Parameters:
7329: + dm - The DM object
7330: . name - The label name
7331: . point - The mesh point
7332: - value - The label value for this point
7334: Output Parameter:
7336: Level: beginner
7338: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7339: @*/
7340: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7341: {
7342: DMLabel label;
7348: DMGetLabel(dm, name, &label);
7349: if (!label) {
7350: DMCreateLabel(dm, name);
7351: DMGetLabel(dm, name, &label);
7352: }
7353: DMLabelSetValue(label, point, value);
7354: return(0);
7355: }
7357: /*@C
7358: DMClearLabelValue - Remove a point from a Sieve Label with given value
7360: Not Collective
7362: Input Parameters:
7363: + dm - The DM object
7364: . name - The label name
7365: . point - The mesh point
7366: - value - The label value for this point
7368: Output Parameter:
7370: Level: beginner
7372: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7373: @*/
7374: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7375: {
7376: DMLabel label;
7382: DMGetLabel(dm, name, &label);
7383: if (!label) return(0);
7384: DMLabelClearValue(label, point, value);
7385: return(0);
7386: }
7388: /*@C
7389: DMGetLabelSize - Get the number of different integer ids in a Label
7391: Not Collective
7393: Input Parameters:
7394: + dm - The DM object
7395: - name - The label name
7397: Output Parameter:
7398: . size - The number of different integer ids, or 0 if the label does not exist
7400: Level: beginner
7402: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7403: @*/
7404: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7405: {
7406: DMLabel label;
7413: DMGetLabel(dm, name, &label);
7414: *size = 0;
7415: if (!label) return(0);
7416: DMLabelGetNumValues(label, size);
7417: return(0);
7418: }
7420: /*@C
7421: DMGetLabelIdIS - Get the integer ids in a label
7423: Not Collective
7425: Input Parameters:
7426: + mesh - The DM object
7427: - name - The label name
7429: Output Parameter:
7430: . ids - The integer ids, or NULL if the label does not exist
7432: Level: beginner
7434: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7435: @*/
7436: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7437: {
7438: DMLabel label;
7445: DMGetLabel(dm, name, &label);
7446: *ids = NULL;
7447: if (label) {
7448: DMLabelGetValueIS(label, ids);
7449: } else {
7450: /* returning an empty IS */
7451: ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7452: }
7453: return(0);
7454: }
7456: /*@C
7457: DMGetStratumSize - Get the number of points in a label stratum
7459: Not Collective
7461: Input Parameters:
7462: + dm - The DM object
7463: . name - The label name
7464: - value - The stratum value
7466: Output Parameter:
7467: . size - The stratum size
7469: Level: beginner
7471: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7472: @*/
7473: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7474: {
7475: DMLabel label;
7482: DMGetLabel(dm, name, &label);
7483: *size = 0;
7484: if (!label) return(0);
7485: DMLabelGetStratumSize(label, value, size);
7486: return(0);
7487: }
7489: /*@C
7490: DMGetStratumIS - Get the points in a label stratum
7492: Not Collective
7494: Input Parameters:
7495: + dm - The DM object
7496: . name - The label name
7497: - value - The stratum value
7499: Output Parameter:
7500: . points - The stratum points, or NULL if the label does not exist or does not have that value
7502: Level: beginner
7504: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7505: @*/
7506: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7507: {
7508: DMLabel label;
7515: DMGetLabel(dm, name, &label);
7516: *points = NULL;
7517: if (!label) return(0);
7518: DMLabelGetStratumIS(label, value, points);
7519: return(0);
7520: }
7522: /*@C
7523: DMSetStratumIS - Set the points in a label stratum
7525: Not Collective
7527: Input Parameters:
7528: + dm - The DM object
7529: . name - The label name
7530: . value - The stratum value
7531: - points - The stratum points
7533: Level: beginner
7535: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7536: @*/
7537: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7538: {
7539: DMLabel label;
7546: DMGetLabel(dm, name, &label);
7547: if (!label) return(0);
7548: DMLabelSetStratumIS(label, value, points);
7549: return(0);
7550: }
7552: /*@C
7553: DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7555: Not Collective
7557: Input Parameters:
7558: + dm - The DM object
7559: . name - The label name
7560: - value - The label value for this point
7562: Output Parameter:
7564: Level: beginner
7566: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7567: @*/
7568: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7569: {
7570: DMLabel label;
7576: DMGetLabel(dm, name, &label);
7577: if (!label) return(0);
7578: DMLabelClearStratum(label, value);
7579: return(0);
7580: }
7582: /*@
7583: DMGetNumLabels - Return the number of labels defined by the mesh
7585: Not Collective
7587: Input Parameter:
7588: . dm - The DM object
7590: Output Parameter:
7591: . numLabels - the number of Labels
7593: Level: intermediate
7595: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7596: @*/
7597: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7598: {
7599: DMLabelLink next = dm->labels;
7600: PetscInt n = 0;
7605: while (next) {++n; next = next->next;}
7606: *numLabels = n;
7607: return(0);
7608: }
7610: /*@C
7611: DMGetLabelName - Return the name of nth label
7613: Not Collective
7615: Input Parameters:
7616: + dm - The DM object
7617: - n - the label number
7619: Output Parameter:
7620: . name - the label name
7622: Level: intermediate
7624: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7625: @*/
7626: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7627: {
7628: DMLabelLink next = dm->labels;
7629: PetscInt l = 0;
7635: while (next) {
7636: if (l == n) {
7637: PetscObjectGetName((PetscObject) next->label, name);
7638: return(0);
7639: }
7640: ++l;
7641: next = next->next;
7642: }
7643: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7644: }
7646: /*@C
7647: DMHasLabel - Determine whether the mesh has a label of a given name
7649: Not Collective
7651: Input Parameters:
7652: + dm - The DM object
7653: - name - The label name
7655: Output Parameter:
7656: . hasLabel - PETSC_TRUE if the label is present
7658: Level: intermediate
7660: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7661: @*/
7662: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7663: {
7664: DMLabelLink next = dm->labels;
7665: const char *lname;
7672: *hasLabel = PETSC_FALSE;
7673: while (next) {
7674: PetscObjectGetName((PetscObject) next->label, &lname);
7675: PetscStrcmp(name, lname, hasLabel);
7676: if (*hasLabel) break;
7677: next = next->next;
7678: }
7679: return(0);
7680: }
7682: /*@C
7683: DMGetLabel - Return the label of a given name, or NULL
7685: Not Collective
7687: Input Parameters:
7688: + dm - The DM object
7689: - name - The label name
7691: Output Parameter:
7692: . label - The DMLabel, or NULL if the label is absent
7694: Note: Some of the default labels in a DMPlex will be
7695: $ "depth" - Holds the depth (co-dimension) of each mesh point
7696: $ "celltype" - Holds the topological type of each cell
7697: $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7698: $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7699: $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7700: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7702: Level: intermediate
7704: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7705: @*/
7706: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7707: {
7708: DMLabelLink next = dm->labels;
7709: PetscBool hasLabel;
7710: const char *lname;
7717: *label = NULL;
7718: while (next) {
7719: PetscObjectGetName((PetscObject) next->label, &lname);
7720: PetscStrcmp(name, lname, &hasLabel);
7721: if (hasLabel) {
7722: *label = next->label;
7723: break;
7724: }
7725: next = next->next;
7726: }
7727: return(0);
7728: }
7730: /*@C
7731: DMGetLabelByNum - Return the nth label
7733: Not Collective
7735: Input Parameters:
7736: + dm - The DM object
7737: - n - the label number
7739: Output Parameter:
7740: . label - the label
7742: Level: intermediate
7744: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7745: @*/
7746: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7747: {
7748: DMLabelLink next = dm->labels;
7749: PetscInt l = 0;
7754: while (next) {
7755: if (l == n) {
7756: *label = next->label;
7757: return(0);
7758: }
7759: ++l;
7760: next = next->next;
7761: }
7762: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7763: }
7765: /*@C
7766: DMAddLabel - Add the label to this mesh
7768: Not Collective
7770: Input Parameters:
7771: + dm - The DM object
7772: - label - The DMLabel
7774: Level: developer
7776: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7777: @*/
7778: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7779: {
7780: DMLabelLink l, *p, tmpLabel;
7781: PetscBool hasLabel;
7782: const char *lname;
7783: PetscBool flg;
7788: PetscObjectGetName((PetscObject) label, &lname);
7789: DMHasLabel(dm, lname, &hasLabel);
7790: if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7791: PetscCalloc1(1, &tmpLabel);
7792: tmpLabel->label = label;
7793: tmpLabel->output = PETSC_TRUE;
7794: for (p=&dm->labels; (l=*p); p=&l->next) {}
7795: *p = tmpLabel;
7796: PetscObjectReference((PetscObject)label);
7797: PetscStrcmp(lname, "depth", &flg);
7798: if (flg) dm->depthLabel = label;
7799: PetscStrcmp(lname, "celltype", &flg);
7800: if (flg) dm->celltypeLabel = label;
7801: return(0);
7802: }
7804: /*@C
7805: DMRemoveLabel - Remove the label given by name from this mesh
7807: Not Collective
7809: Input Parameters:
7810: + dm - The DM object
7811: - name - The label name
7813: Output Parameter:
7814: . label - The DMLabel, or NULL if the label is absent
7816: Level: developer
7818: Notes:
7819: DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7820: DMLabelDestroy() on the label.
7822: DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7823: call DMLabelDestroy(). Instead, the label is returned and the user is
7824: responsible of calling DMLabelDestroy() at some point.
7826: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7827: @*/
7828: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7829: {
7830: DMLabelLink link, *pnext;
7831: PetscBool hasLabel;
7832: const char *lname;
7838: if (label) {
7840: *label = NULL;
7841: }
7842: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7843: PetscObjectGetName((PetscObject) link->label, &lname);
7844: PetscStrcmp(name, lname, &hasLabel);
7845: if (hasLabel) {
7846: *pnext = link->next; /* Remove from list */
7847: PetscStrcmp(name, "depth", &hasLabel);
7848: if (hasLabel) dm->depthLabel = NULL;
7849: PetscStrcmp(name, "celltype", &hasLabel);
7850: if (hasLabel) dm->celltypeLabel = NULL;
7851: if (label) *label = link->label;
7852: else {DMLabelDestroy(&link->label);}
7853: PetscFree(link);
7854: break;
7855: }
7856: }
7857: return(0);
7858: }
7860: /*@
7861: DMRemoveLabelBySelf - Remove the label from this mesh
7863: Not Collective
7865: Input Parameters:
7866: + dm - The DM object
7867: . label - (Optional) The DMLabel to be removed from the DM
7868: - failNotFound - Should it fail if the label is not found in the DM?
7870: Level: developer
7872: Notes:
7873: Only exactly the same instance is removed if found, name match is ignored.
7874: If the DM has an exclusive reference to the label, it gets destroyed and
7875: *label nullified.
7877: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7878: @*/
7879: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7880: {
7881: DMLabelLink link, *pnext;
7882: PetscBool hasLabel = PETSC_FALSE;
7888: if (!*label && !failNotFound) return(0);
7891: for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7892: if (*label == link->label) {
7893: hasLabel = PETSC_TRUE;
7894: *pnext = link->next; /* Remove from list */
7895: if (*label == dm->depthLabel) dm->depthLabel = NULL;
7896: if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7897: if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7898: DMLabelDestroy(&link->label);
7899: PetscFree(link);
7900: break;
7901: }
7902: }
7903: if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7904: return(0);
7905: }
7907: /*@C
7908: DMGetLabelOutput - Get the output flag for a given label
7910: Not Collective
7912: Input Parameters:
7913: + dm - The DM object
7914: - name - The label name
7916: Output Parameter:
7917: . output - The flag for output
7919: Level: developer
7921: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7922: @*/
7923: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7924: {
7925: DMLabelLink next = dm->labels;
7926: const char *lname;
7933: while (next) {
7934: PetscBool flg;
7936: PetscObjectGetName((PetscObject) next->label, &lname);
7937: PetscStrcmp(name, lname, &flg);
7938: if (flg) {*output = next->output; return(0);}
7939: next = next->next;
7940: }
7941: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7942: }
7944: /*@C
7945: DMSetLabelOutput - Set the output flag for a given label
7947: Not Collective
7949: Input Parameters:
7950: + dm - The DM object
7951: . name - The label name
7952: - output - The flag for output
7954: Level: developer
7956: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7957: @*/
7958: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7959: {
7960: DMLabelLink next = dm->labels;
7961: const char *lname;
7967: while (next) {
7968: PetscBool flg;
7970: PetscObjectGetName((PetscObject) next->label, &lname);
7971: PetscStrcmp(name, lname, &flg);
7972: if (flg) {next->output = output; return(0);}
7973: next = next->next;
7974: }
7975: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7976: }
7978: /*@
7979: DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7981: Collective on dmA
7983: Input Parameter:
7984: + dmA - The DM object with initial labels
7985: . dmB - The DM object with copied labels
7986: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7987: - all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7989: Level: intermediate
7991: Note: This is typically used when interpolating or otherwise adding to a mesh
7993: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7994: @*/
7995: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7996: {
7997: DMLabel label, labelNew;
7998: const char *name;
7999: PetscBool flg;
8000: DMLabelLink link;
8008: if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8009: if (dmA == dmB) return(0);
8010: for (link=dmA->labels; link; link=link->next) {
8011: label=link->label;
8012: PetscObjectGetName((PetscObject)label, &name);
8013: if (!all) {
8014: PetscStrcmp(name, "depth", &flg);
8015: if (flg) continue;
8016: PetscStrcmp(name, "dim", &flg);
8017: if (flg) continue;
8018: PetscStrcmp(name, "celltype", &flg);
8019: if (flg) continue;
8020: }
8021: if (mode==PETSC_COPY_VALUES) {
8022: DMLabelDuplicate(label, &labelNew);
8023: } else {
8024: labelNew = label;
8025: }
8026: DMAddLabel(dmB, labelNew);
8027: if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8028: }
8029: return(0);
8030: }
8031: /*
8032: Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8033: like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8034: (label, id) pair in the DM.
8036: However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8037: each label.
8038: */
8039: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8040: {
8041: DMUniversalLabel ul;
8042: PetscBool *active;
8043: PetscInt pStart, pEnd, p, Nl, l, m;
8044: PetscErrorCode ierr;
8047: PetscMalloc1(1, &ul);
8048: DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8049: DMGetNumLabels(dm, &Nl);
8050: PetscCalloc1(Nl, &active);
8051: ul->Nl = 0;
8052: for (l = 0; l < Nl; ++l) {
8053: PetscBool isdepth, iscelltype;
8054: const char *name;
8056: DMGetLabelName(dm, l, &name);
8057: PetscStrncmp(name, "depth", 6, &isdepth);
8058: PetscStrncmp(name, "celltype", 9, &iscelltype);
8059: active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8060: if (active[l]) ++ul->Nl;
8061: }
8062: PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8063: ul->Nv = 0;
8064: for (l = 0, m = 0; l < Nl; ++l) {
8065: DMLabel label;
8066: PetscInt nv;
8067: const char *name;
8069: if (!active[l]) continue;
8070: DMGetLabelName(dm, l, &name);
8071: DMGetLabelByNum(dm, l, &label);
8072: DMLabelGetNumValues(label, &nv);
8073: PetscStrallocpy(name, &ul->names[m]);
8074: ul->indices[m] = l;
8075: ul->Nv += nv;
8076: ul->offsets[m+1] = nv;
8077: ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1));
8078: ++m;
8079: }
8080: for (l = 1; l <= ul->Nl; ++l) {
8081: ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8082: ul->bits[l] = ul->bits[l-1] + ul->bits[l];
8083: }
8084: for (l = 0; l < ul->Nl; ++l) {
8085: PetscInt b;
8087: ul->masks[l] = 0;
8088: for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8089: }
8090: PetscMalloc1(ul->Nv, &ul->values);
8091: for (l = 0, m = 0; l < Nl; ++l) {
8092: DMLabel label;
8093: IS valueIS;
8094: const PetscInt *varr;
8095: PetscInt nv, v;
8097: if (!active[l]) continue;
8098: DMGetLabelByNum(dm, l, &label);
8099: DMLabelGetNumValues(label, &nv);
8100: DMLabelGetValueIS(label, &valueIS);
8101: ISGetIndices(valueIS, &varr);
8102: for (v = 0; v < nv; ++v) {
8103: ul->values[ul->offsets[m]+v] = varr[v];
8104: }
8105: ISRestoreIndices(valueIS, &varr);
8106: ISDestroy(&valueIS);
8107: PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8108: ++m;
8109: }
8110: DMPlexGetChart(dm, &pStart, &pEnd);
8111: for (p = pStart; p < pEnd; ++p) {
8112: PetscInt uval = 0;
8113: PetscBool marked = PETSC_FALSE;
8115: for (l = 0, m = 0; l < Nl; ++l) {
8116: DMLabel label;
8117: PetscInt val, defval, loc, nv;
8119: if (!active[l]) continue;
8120: DMGetLabelByNum(dm, l, &label);
8121: DMLabelGetValue(label, p, &val);
8122: DMLabelGetDefaultValue(label, &defval);
8123: if (val == defval) {++m; continue;}
8124: nv = ul->offsets[m+1]-ul->offsets[m];
8125: marked = PETSC_TRUE;
8126: PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8127: if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8128: uval += (loc+1) << ul->bits[m];
8129: ++m;
8130: }
8131: if (marked) {DMLabelSetValue(ul->label, p, uval);}
8132: }
8133: PetscFree(active);
8134: *universal = ul;
8135: return(0);
8136: }
8138: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8139: {
8140: PetscInt l;
8144: for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8145: DMLabelDestroy(&(*universal)->label);
8146: PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8147: PetscFree((*universal)->values);
8148: PetscFree(*universal);
8149: *universal = NULL;
8150: return(0);
8151: }
8153: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8154: {
8157: *ulabel = ul->label;
8158: return(0);
8159: }
8161: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8162: {
8163: PetscInt Nl = ul->Nl, l;
8168: for (l = 0; l < Nl; ++l) {
8169: if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8170: else {DMCreateLabel(dm, ul->names[l]);}
8171: }
8172: if (preserveOrder) {
8173: for (l = 0; l < ul->Nl; ++l) {
8174: const char *name;
8175: PetscBool match;
8177: DMGetLabelName(dm, ul->indices[l], &name);
8178: PetscStrcmp(name, ul->names[l], &match);
8179: 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]);
8180: }
8181: }
8182: return(0);
8183: }
8185: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8186: {
8187: PetscInt l;
8191: for (l = 0; l < ul->Nl; ++l) {
8192: DMLabel label;
8193: PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8195: if (lval) {
8196: if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8197: else {DMGetLabel(dm, ul->names[l], &label);}
8198: DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8199: }
8200: }
8201: return(0);
8202: }
8204: /*@
8205: DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8207: Input Parameter:
8208: . dm - The DM object
8210: Output Parameter:
8211: . cdm - The coarse DM
8213: Level: intermediate
8215: .seealso: DMSetCoarseDM()
8216: @*/
8217: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8218: {
8222: *cdm = dm->coarseMesh;
8223: return(0);
8224: }
8226: /*@
8227: DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8229: Input Parameters:
8230: + dm - The DM object
8231: - cdm - The coarse DM
8233: Level: intermediate
8235: .seealso: DMGetCoarseDM()
8236: @*/
8237: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8238: {
8244: PetscObjectReference((PetscObject)cdm);
8245: DMDestroy(&dm->coarseMesh);
8246: dm->coarseMesh = cdm;
8247: return(0);
8248: }
8250: /*@
8251: DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8253: Input Parameter:
8254: . dm - The DM object
8256: Output Parameter:
8257: . fdm - The fine DM
8259: Level: intermediate
8261: .seealso: DMSetFineDM()
8262: @*/
8263: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8264: {
8268: *fdm = dm->fineMesh;
8269: return(0);
8270: }
8272: /*@
8273: DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8275: Input Parameters:
8276: + dm - The DM object
8277: - fdm - The fine DM
8279: Level: intermediate
8281: .seealso: DMGetFineDM()
8282: @*/
8283: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8284: {
8290: PetscObjectReference((PetscObject)fdm);
8291: DMDestroy(&dm->fineMesh);
8292: dm->fineMesh = fdm;
8293: return(0);
8294: }
8296: /*=== DMBoundary code ===*/
8298: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
8299: {
8300: PetscInt d;
8304: for (d = 0; d < dm->Nds; ++d) {
8305: PetscDSCopyBoundary(dm->probs[d].ds, PETSC_DETERMINE, NULL, dmNew->probs[d].ds);
8306: }
8307: return(0);
8308: }
8310: /*@C
8311: DMAddBoundary - Add a boundary condition to the model
8313: Collective on dm
8315: Input Parameters:
8316: + dm - The DM, with a PetscDS that matches the problem being constrained
8317: . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8318: . name - The BC name
8319: . labelname - The label defining constrained points
8320: . field - The field to constrain
8321: . numcomps - The number of constrained field components (0 will constrain all fields)
8322: . comps - An array of constrained component numbers
8323: . bcFunc - A pointwise function giving boundary values
8324: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8325: . numids - The number of DMLabel ids for constrained points
8326: . ids - An array of ids for constrained points
8327: - ctx - An optional user context for bcFunc
8329: Options Database Keys:
8330: + -bc_<boundary name> <num> - Overrides the boundary ids
8331: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8333: Note:
8334: Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8336: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8338: If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8340: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8341: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8342: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8343: $ PetscReal time, const PetscReal x[], PetscScalar bcval[])
8345: + dim - the spatial dimension
8346: . Nf - the number of fields
8347: . uOff - the offset into u[] and u_t[] for each field
8348: . uOff_x - the offset into u_x[] for each field
8349: . u - each field evaluated at the current point
8350: . u_t - the time derivative of each field evaluated at the current point
8351: . u_x - the gradient of each field evaluated at the current point
8352: . aOff - the offset into a[] and a_t[] for each auxiliary field
8353: . aOff_x - the offset into a_x[] for each auxiliary field
8354: . a - each auxiliary field evaluated at the current point
8355: . a_t - the time derivative of each auxiliary field evaluated at the current point
8356: . a_x - the gradient of auxiliary each field evaluated at the current point
8357: . t - current time
8358: . x - coordinates of the current point
8359: . numConstants - number of constant parameters
8360: . constants - constant parameters
8361: - bcval - output values at the current point
8363: Level: developer
8365: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8366: @*/
8367: 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)
8368: {
8369: PetscDS ds;
8378: DMGetDS(dm, &ds);
8379: DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8380: PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8381: return(0);
8382: }
8384: /*@
8385: DMGetNumBoundary - Get the number of registered BC
8387: Input Parameters:
8388: . dm - The mesh object
8390: Output Parameters:
8391: . numBd - The number of BC
8393: Level: intermediate
8395: .seealso: DMAddBoundary(), DMGetBoundary()
8396: @*/
8397: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8398: {
8399: PetscDS ds;
8404: DMGetDS(dm, &ds);
8405: PetscDSGetNumBoundary(ds, numBd);
8406: return(0);
8407: }
8409: /*@C
8410: DMGetBoundary - Get a model boundary condition
8412: Input Parameters:
8413: + dm - The mesh object
8414: - bd - The BC number
8416: Output Parameters:
8417: + type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8418: . name - The BC name
8419: . labelname - The label defining constrained points
8420: . field - The field to constrain
8421: . numcomps - The number of constrained field components
8422: . comps - An array of constrained component numbers
8423: . bcFunc - A pointwise function giving boundary values
8424: . bcFunc_t - A pointwise function giving the time derviative of the boundary values
8425: . numids - The number of DMLabel ids for constrained points
8426: . ids - An array of ids for constrained points
8427: - ctx - An optional user context for bcFunc
8429: Options Database Keys:
8430: + -bc_<boundary name> <num> - Overrides the boundary ids
8431: - -bc_<boundary name>_comp <num> - Overrides the boundary components
8433: Level: developer
8435: .seealso: DMAddBoundary()
8436: @*/
8437: 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)
8438: {
8439: PetscDS ds;
8444: DMGetDS(dm, &ds);
8445: PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8446: return(0);
8447: }
8449: static PetscErrorCode DMPopulateBoundary(DM dm)
8450: {
8451: PetscDS ds;
8452: DMBoundary *lastnext;
8453: DSBoundary dsbound;
8457: DMGetDS(dm, &ds);
8458: dsbound = ds->boundary;
8459: if (dm->boundary) {
8460: DMBoundary next = dm->boundary;
8462: /* quick check to see if the PetscDS has changed */
8463: if (next->dsboundary == dsbound) return(0);
8464: /* the PetscDS has changed: tear down and rebuild */
8465: while (next) {
8466: DMBoundary b = next;
8468: next = b->next;
8469: PetscFree(b);
8470: }
8471: dm->boundary = NULL;
8472: }
8474: lastnext = &(dm->boundary);
8475: while (dsbound) {
8476: DMBoundary dmbound;
8478: PetscNew(&dmbound);
8479: dmbound->dsboundary = dsbound;
8480: DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8481: if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8482: /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8483: *lastnext = dmbound;
8484: lastnext = &(dmbound->next);
8485: dsbound = dsbound->next;
8486: }
8487: return(0);
8488: }
8490: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8491: {
8492: DMBoundary b;
8498: *isBd = PETSC_FALSE;
8499: DMPopulateBoundary(dm);
8500: b = dm->boundary;
8501: while (b && !(*isBd)) {
8502: DMLabel label = b->label;
8503: DSBoundary dsb = b->dsboundary;
8505: if (label) {
8506: PetscInt i;
8508: for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8509: DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8510: }
8511: }
8512: b = b->next;
8513: }
8514: return(0);
8515: }
8517: /*@C
8518: DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8520: Collective on DM
8522: Input Parameters:
8523: + dm - The DM
8524: . time - The time
8525: . funcs - The coordinate functions to evaluate, one per field
8526: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8527: - mode - The insertion mode for values
8529: Output Parameter:
8530: . X - vector
8532: Calling sequence of func:
8533: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8535: + dim - The spatial dimension
8536: . time - The time at which to sample
8537: . x - The coordinates
8538: . Nf - The number of fields
8539: . u - The output field values
8540: - ctx - optional user-defined function context
8542: Level: developer
8544: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8545: @*/
8546: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8547: {
8548: Vec localX;
8553: DMGetLocalVector(dm, &localX);
8554: DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8555: DMLocalToGlobalBegin(dm, localX, mode, X);
8556: DMLocalToGlobalEnd(dm, localX, mode, X);
8557: DMRestoreLocalVector(dm, &localX);
8558: return(0);
8559: }
8561: /*@C
8562: DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8564: Not collective
8566: Input Parameters:
8567: + dm - The DM
8568: . time - The time
8569: . funcs - The coordinate functions to evaluate, one per field
8570: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8571: - mode - The insertion mode for values
8573: Output Parameter:
8574: . localX - vector
8576: Calling sequence of func:
8577: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8579: + dim - The spatial dimension
8580: . x - The coordinates
8581: . Nf - The number of fields
8582: . u - The output field values
8583: - ctx - optional user-defined function context
8585: Level: developer
8587: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8588: @*/
8589: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8590: {
8596: if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8597: (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8598: return(0);
8599: }
8601: /*@C
8602: 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.
8604: Collective on DM
8606: Input Parameters:
8607: + dm - The DM
8608: . time - The time
8609: . label - The DMLabel selecting the portion of the mesh for projection
8610: . funcs - The coordinate functions to evaluate, one per field
8611: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8612: - mode - The insertion mode for values
8614: Output Parameter:
8615: . X - vector
8617: Calling sequence of func:
8618: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8620: + dim - The spatial dimension
8621: . x - The coordinates
8622: . Nf - The number of fields
8623: . u - The output field values
8624: - ctx - optional user-defined function context
8626: Level: developer
8628: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8629: @*/
8630: 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)
8631: {
8632: Vec localX;
8637: DMGetLocalVector(dm, &localX);
8638: DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8639: DMLocalToGlobalBegin(dm, localX, mode, X);
8640: DMLocalToGlobalEnd(dm, localX, mode, X);
8641: DMRestoreLocalVector(dm, &localX);
8642: return(0);
8643: }
8645: /*@C
8646: 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.
8648: Not collective
8650: Input Parameters:
8651: + dm - The DM
8652: . time - The time
8653: . label - The DMLabel selecting the portion of the mesh for projection
8654: . funcs - The coordinate functions to evaluate, one per field
8655: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8656: - mode - The insertion mode for values
8658: Output Parameter:
8659: . localX - vector
8661: Calling sequence of func:
8662: $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8664: + dim - The spatial dimension
8665: . x - The coordinates
8666: . Nf - The number of fields
8667: . u - The output field values
8668: - ctx - optional user-defined function context
8670: Level: developer
8672: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8673: @*/
8674: 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)
8675: {
8681: if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8682: (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8683: return(0);
8684: }
8686: /*@C
8687: DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8689: Not collective
8691: Input Parameters:
8692: + dm - The DM
8693: . time - The time
8694: . localU - The input field vector
8695: . funcs - The functions to evaluate, one per field
8696: - mode - The insertion mode for values
8698: Output Parameter:
8699: . localX - The output vector
8701: Calling sequence of func:
8702: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8703: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8704: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8705: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8707: + dim - The spatial dimension
8708: . Nf - The number of input fields
8709: . NfAux - The number of input auxiliary fields
8710: . uOff - The offset of each field in u[]
8711: . uOff_x - The offset of each field in u_x[]
8712: . u - The field values at this point in space
8713: . u_t - The field time derivative at this point in space (or NULL)
8714: . u_x - The field derivatives at this point in space
8715: . aOff - The offset of each auxiliary field in u[]
8716: . aOff_x - The offset of each auxiliary field in u_x[]
8717: . a - The auxiliary field values at this point in space
8718: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8719: . a_x - The auxiliary field derivatives at this point in space
8720: . t - The current time
8721: . x - The coordinates of this point
8722: . numConstants - The number of constants
8723: . constants - The value of each constant
8724: - f - The value of the function at this point in space
8726: 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.
8727: 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
8728: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8729: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8731: Level: intermediate
8733: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8734: @*/
8735: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8736: void (**funcs)(PetscInt, PetscInt, PetscInt,
8737: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8738: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8739: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8740: InsertMode mode, Vec localX)
8741: {
8748: if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8749: (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8750: return(0);
8751: }
8753: /*@C
8754: 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.
8756: Not collective
8758: Input Parameters:
8759: + dm - The DM
8760: . time - The time
8761: . label - The DMLabel marking the portion of the domain to output
8762: . numIds - The number of label ids to use
8763: . ids - The label ids to use for marking
8764: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8765: . comps - The components to set in the output, or NULL for all components
8766: . localU - The input field vector
8767: . funcs - The functions to evaluate, one per field
8768: - mode - The insertion mode for values
8770: Output Parameter:
8771: . localX - The output vector
8773: Calling sequence of func:
8774: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8775: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8776: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8777: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8779: + dim - The spatial dimension
8780: . Nf - The number of input fields
8781: . NfAux - The number of input auxiliary fields
8782: . uOff - The offset of each field in u[]
8783: . uOff_x - The offset of each field in u_x[]
8784: . u - The field values at this point in space
8785: . u_t - The field time derivative at this point in space (or NULL)
8786: . u_x - The field derivatives at this point in space
8787: . aOff - The offset of each auxiliary field in u[]
8788: . aOff_x - The offset of each auxiliary field in u_x[]
8789: . a - The auxiliary field values at this point in space
8790: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8791: . a_x - The auxiliary field derivatives at this point in space
8792: . t - The current time
8793: . x - The coordinates of this point
8794: . numConstants - The number of constants
8795: . constants - The value of each constant
8796: - f - The value of the function at this point in space
8798: 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.
8799: 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
8800: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8801: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8803: Level: intermediate
8805: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8806: @*/
8807: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8808: void (**funcs)(PetscInt, PetscInt, PetscInt,
8809: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8810: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8811: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8812: InsertMode mode, Vec localX)
8813: {
8820: if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8821: (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8822: return(0);
8823: }
8825: /*@C
8826: 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.
8828: Not collective
8830: Input Parameters:
8831: + dm - The DM
8832: . time - The time
8833: . label - The DMLabel marking the portion of the domain boundary to output
8834: . numIds - The number of label ids to use
8835: . ids - The label ids to use for marking
8836: . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components
8837: . comps - The components to set in the output, or NULL for all components
8838: . localU - The input field vector
8839: . funcs - The functions to evaluate, one per field
8840: - mode - The insertion mode for values
8842: Output Parameter:
8843: . localX - The output vector
8845: Calling sequence of func:
8846: $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8847: $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8848: $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8849: $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8851: + dim - The spatial dimension
8852: . Nf - The number of input fields
8853: . NfAux - The number of input auxiliary fields
8854: . uOff - The offset of each field in u[]
8855: . uOff_x - The offset of each field in u_x[]
8856: . u - The field values at this point in space
8857: . u_t - The field time derivative at this point in space (or NULL)
8858: . u_x - The field derivatives at this point in space
8859: . aOff - The offset of each auxiliary field in u[]
8860: . aOff_x - The offset of each auxiliary field in u_x[]
8861: . a - The auxiliary field values at this point in space
8862: . a_t - The auxiliary field time derivative at this point in space (or NULL)
8863: . a_x - The auxiliary field derivatives at this point in space
8864: . t - The current time
8865: . x - The coordinates of this point
8866: . n - The face normal
8867: . numConstants - The number of constants
8868: . constants - The value of each constant
8869: - f - The value of the function at this point in space
8871: Note:
8872: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8873: 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
8874: a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8875: auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8877: Level: intermediate
8879: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8880: @*/
8881: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8882: void (**funcs)(PetscInt, PetscInt, PetscInt,
8883: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8884: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8885: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8886: InsertMode mode, Vec localX)
8887: {
8894: if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8895: (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8896: return(0);
8897: }
8899: /*@C
8900: DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8902: Input Parameters:
8903: + dm - The DM
8904: . time - The time
8905: . funcs - The functions to evaluate for each field component
8906: . ctxs - Optional array of contexts to pass to each function, or NULL.
8907: - X - The coefficient vector u_h, a global vector
8909: Output Parameter:
8910: . diff - The diff ||u - u_h||_2
8912: Level: developer
8914: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8915: @*/
8916: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8917: {
8923: if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8924: (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8925: return(0);
8926: }
8928: /*@C
8929: DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8931: Collective on dm
8933: Input Parameters:
8934: + dm - The DM
8935: , time - The time
8936: . funcs - The gradient functions to evaluate for each field component
8937: . ctxs - Optional array of contexts to pass to each function, or NULL.
8938: . X - The coefficient vector u_h, a global vector
8939: - n - The vector to project along
8941: Output Parameter:
8942: . diff - The diff ||(grad u - grad u_h) . n||_2
8944: Level: developer
8946: .seealso: DMProjectFunction(), DMComputeL2Diff()
8947: @*/
8948: 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)
8949: {
8955: if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8956: (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8957: return(0);
8958: }
8960: /*@C
8961: DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8963: Collective on dm
8965: Input Parameters:
8966: + dm - The DM
8967: . time - The time
8968: . funcs - The functions to evaluate for each field component
8969: . ctxs - Optional array of contexts to pass to each function, or NULL.
8970: - X - The coefficient vector u_h, a global vector
8972: Output Parameter:
8973: . diff - The array of differences, ||u^f - u^f_h||_2
8975: Level: developer
8977: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8978: @*/
8979: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8980: {
8986: if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8987: (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8988: return(0);
8989: }
8991: /*@C
8992: DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags. Specific implementations of DM maybe have
8993: specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8995: Collective on dm
8997: Input parameters:
8998: + dm - the pre-adaptation DM object
8999: - label - label with the flags
9001: Output parameters:
9002: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
9004: Level: intermediate
9006: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9007: @*/
9008: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9009: {
9016: *dmAdapt = NULL;
9017: if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9018: (dm->ops->adaptlabel)(dm, label, dmAdapt);
9019: if (*dmAdapt) {
9020: (*dmAdapt)->prealloc_only = dm->prealloc_only; /* maybe this should go .... */
9021: PetscFree((*dmAdapt)->vectype);
9022: PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9023: PetscFree((*dmAdapt)->mattype);
9024: PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9025: }
9026: return(0);
9027: }
9029: /*@C
9030: DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
9032: Input Parameters:
9033: + dm - The DM object
9034: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9035: - 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_".
9037: Output Parameter:
9038: . dmAdapt - Pointer to the DM object containing the adapted mesh
9040: Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
9042: Level: advanced
9044: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9045: @*/
9046: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9047: {
9055: *dmAdapt = NULL;
9056: if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9057: (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9058: return(0);
9059: }
9061: /*@C
9062: DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9064: Not Collective
9066: Input Parameter:
9067: . dm - The DM
9069: Output Parameters:
9070: + nranks - the number of neighbours
9071: - ranks - the neighbors ranks
9073: Notes:
9074: Do not free the array, it is freed when the DM is destroyed.
9076: Level: beginner
9078: .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9079: @*/
9080: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9081: {
9086: if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9087: (dm->ops->getneighbors)(dm,nranks,ranks);
9088: return(0);
9089: }
9091: #include <petsc/private/matimpl.h>
9093: /*
9094: Converts the input vector to a ghosted vector and then calls the standard coloring code.
9095: This has be a different function because it requires DM which is not defined in the Mat library
9096: */
9097: PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9098: {
9102: if (coloring->ctype == IS_COLORING_LOCAL) {
9103: Vec x1local;
9104: DM dm;
9105: MatGetDM(J,&dm);
9106: if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9107: DMGetLocalVector(dm,&x1local);
9108: DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9109: DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9110: x1 = x1local;
9111: }
9112: MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9113: if (coloring->ctype == IS_COLORING_LOCAL) {
9114: DM dm;
9115: MatGetDM(J,&dm);
9116: DMRestoreLocalVector(dm,&x1);
9117: }
9118: return(0);
9119: }
9121: /*@
9122: MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9124: Input Parameter:
9125: . coloring - the MatFDColoring object
9127: Developer Notes:
9128: this routine exists because the PETSc Mat library does not know about the DM objects
9130: Level: advanced
9132: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9133: @*/
9134: PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9135: {
9137: coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9138: return(0);
9139: }
9141: /*@
9142: DMGetCompatibility - determine if two DMs are compatible
9144: Collective
9146: Input Parameters:
9147: + dm1 - the first DM
9148: - dm2 - the second DM
9150: Output Parameters:
9151: + compatible - whether or not the two DMs are compatible
9152: - set - whether or not the compatible value was set
9154: Notes:
9155: Two DMs are deemed compatible if they represent the same parallel decomposition
9156: of the same topology. This implies that the section (field data) on one
9157: "makes sense" with respect to the topology and parallel decomposition of the other.
9158: Loosely speaking, compatible DMs represent the same domain and parallel
9159: decomposition, but hold different data.
9161: Typically, one would confirm compatibility if intending to simultaneously iterate
9162: over a pair of vectors obtained from different DMs.
9164: For example, two DMDA objects are compatible if they have the same local
9165: and global sizes and the same stencil width. They can have different numbers
9166: of degrees of freedom per node. Thus, one could use the node numbering from
9167: either DM in bounds for a loop over vectors derived from either DM.
9169: Consider the operation of summing data living on a 2-dof DMDA to data living
9170: on a 1-dof DMDA, which should be compatible, as in the following snippet.
9171: .vb
9172: ...
9173: DMGetCompatibility(da1,da2,&compatible,&set);
9174: if (set && compatible) {
9175: DMDAVecGetArrayDOF(da1,vec1,&arr1);
9176: DMDAVecGetArrayDOF(da2,vec2,&arr2);
9177: DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9178: for (j=y; j<y+n; ++j) {
9179: for (i=x; i<x+m, ++i) {
9180: arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9181: }
9182: }
9183: DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9184: DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9185: } else {
9186: SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9187: }
9188: ...
9189: .ve
9191: Checking compatibility might be expensive for a given implementation of DM,
9192: or might be impossible to unambiguously confirm or deny. For this reason,
9193: this function may decline to determine compatibility, and hence users should
9194: always check the "set" output parameter.
9196: A DM is always compatible with itself.
9198: In the current implementation, DMs which live on "unequal" communicators
9199: (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9200: incompatible.
9202: This function is labeled "Collective," as information about all subdomains
9203: is required on each rank. However, in DM implementations which store all this
9204: information locally, this function may be merely "Logically Collective".
9206: Developer Notes:
9207: Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9208: iff B is compatible with A. Thus, this function checks the implementations
9209: of both dm and dmc (if they are of different types), attempting to determine
9210: compatibility. It is left to DM implementers to ensure that symmetry is
9211: preserved. The simplest way to do this is, when implementing type-specific
9212: logic for this function, is to check for existing logic in the implementation
9213: of other DM types and let *set = PETSC_FALSE if found.
9215: Level: advanced
9217: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9218: @*/
9220: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9221: {
9223: PetscMPIInt compareResult;
9224: DMType type,type2;
9225: PetscBool sameType;
9231: /* Declare a DM compatible with itself */
9232: if (dm1 == dm2) {
9233: *set = PETSC_TRUE;
9234: *compatible = PETSC_TRUE;
9235: return(0);
9236: }
9238: /* Declare a DM incompatible with a DM that lives on an "unequal"
9239: communicator. Note that this does not preclude compatibility with
9240: DMs living on "congruent" or "similar" communicators, but this must be
9241: determined by the implementation-specific logic */
9242: MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9243: if (compareResult == MPI_UNEQUAL) {
9244: *set = PETSC_TRUE;
9245: *compatible = PETSC_FALSE;
9246: return(0);
9247: }
9249: /* Pass to the implementation-specific routine, if one exists. */
9250: if (dm1->ops->getcompatibility) {
9251: (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9252: if (*set) return(0);
9253: }
9255: /* If dm1 and dm2 are of different types, then attempt to check compatibility
9256: with an implementation of this function from dm2 */
9257: DMGetType(dm1,&type);
9258: DMGetType(dm2,&type2);
9259: PetscStrcmp(type,type2,&sameType);
9260: if (!sameType && dm2->ops->getcompatibility) {
9261: (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9262: } else {
9263: *set = PETSC_FALSE;
9264: }
9265: return(0);
9266: }
9268: /*@C
9269: DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9271: Logically Collective on DM
9273: Input Parameters:
9274: + DM - the DM
9275: . f - the monitor function
9276: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9277: - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9279: Options Database Keys:
9280: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9281: does not cancel those set via the options database.
9283: Notes:
9284: Several different monitoring routines may be set by calling
9285: DMMonitorSet() multiple times; all will be called in the
9286: order in which they were set.
9288: Fortran Notes:
9289: Only a single monitor function can be set for each DM object
9291: Level: intermediate
9293: .seealso: DMMonitorCancel()
9294: @*/
9295: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9296: {
9297: PetscInt m;
9302: for (m = 0; m < dm->numbermonitors; ++m) {
9303: PetscBool identical;
9305: PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9306: if (identical) return(0);
9307: }
9308: if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9309: dm->monitor[dm->numbermonitors] = f;
9310: dm->monitordestroy[dm->numbermonitors] = monitordestroy;
9311: dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9312: return(0);
9313: }
9315: /*@
9316: DMMonitorCancel - Clears all the monitor functions for a DM object.
9318: Logically Collective on DM
9320: Input Parameter:
9321: . dm - the DM
9323: Options Database Key:
9324: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9325: into a code by calls to DMonitorSet(), but does not cancel those
9326: set via the options database
9328: Notes:
9329: There is no way to clear one specific monitor from a DM object.
9331: Level: intermediate
9333: .seealso: DMMonitorSet()
9334: @*/
9335: PetscErrorCode DMMonitorCancel(DM dm)
9336: {
9338: PetscInt m;
9342: for (m = 0; m < dm->numbermonitors; ++m) {
9343: if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9344: }
9345: dm->numbermonitors = 0;
9346: return(0);
9347: }
9349: /*@C
9350: DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9352: Collective on DM
9354: Input Parameters:
9355: + dm - DM object you wish to monitor
9356: . name - the monitor type one is seeking
9357: . help - message indicating what monitoring is done
9358: . manual - manual page for the monitor
9359: . monitor - the monitor function
9360: - 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
9362: Output Parameter:
9363: . flg - Flag set if the monitor was created
9365: Level: developer
9367: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9368: PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9369: PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9370: PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9371: PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9372: PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9373: PetscOptionsFList(), PetscOptionsEList()
9374: @*/
9375: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9376: {
9377: PetscViewer viewer;
9378: PetscViewerFormat format;
9379: PetscErrorCode ierr;
9383: PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9384: if (*flg) {
9385: PetscViewerAndFormat *vf;
9387: PetscViewerAndFormatCreate(viewer, format, &vf);
9388: PetscObjectDereference((PetscObject) viewer);
9389: if (monitorsetup) {(*monitorsetup)(dm, vf);}
9390: DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9391: }
9392: return(0);
9393: }
9395: /*@
9396: DMMonitor - runs the user provided monitor routines, if they exist
9398: Collective on DM
9400: Input Parameters:
9401: . dm - The DM
9403: Level: developer
9405: .seealso: DMMonitorSet()
9406: @*/
9407: PetscErrorCode DMMonitor(DM dm)
9408: {
9409: PetscInt m;
9413: if (!dm) return(0);
9415: for (m = 0; m < dm->numbermonitors; ++m) {
9416: (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9417: }
9418: return(0);
9419: }
9421: /*@
9422: DMComputeError - Computes the error assuming the user has given exact solution functions
9424: Collective on DM
9426: Input Parameters:
9427: + dm - The DM
9428: . sol - The solution vector
9429: . errors - An array of length Nf, the number of fields, or NULL for no output
9430: - errorVec - A Vec pointer, or NULL for no output
9432: Output Parameters:
9433: + errors - The error in each field
9434: - errorVec - Creates a vector to hold the cellwise error
9436: Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9438: Level: developer
9440: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9441: @*/
9442: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9443: {
9444: PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9445: void **ctxs;
9446: PetscReal time;
9447: PetscInt Nf, f, Nds, s;
9448: PetscErrorCode ierr;
9451: DMGetNumFields(dm, &Nf);
9452: PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9453: DMGetNumDS(dm, &Nds);
9454: for (s = 0; s < Nds; ++s) {
9455: PetscDS ds;
9456: DMLabel label;
9457: IS fieldIS;
9458: const PetscInt *fields;
9459: PetscInt dsNf;
9461: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9462: PetscDSGetNumFields(ds, &dsNf);
9463: if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9464: for (f = 0; f < dsNf; ++f) {
9465: const PetscInt field = fields[f];
9466: PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9467: }
9468: if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9469: }
9470: for (f = 0; f < Nf; ++f) {
9471: 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);
9472: }
9473: DMGetOutputSequenceNumber(dm, NULL, &time);
9474: if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9475: if (errorVec) {
9476: DM edm;
9477: DMPolytopeType ct;
9478: PetscBool simplex;
9479: PetscInt dim, cStart, Nf;
9481: DMClone(dm, &edm);
9482: DMGetDimension(edm, &dim);
9483: DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9484: DMPlexGetCellType(dm, cStart, &ct);
9485: simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9486: DMGetNumFields(dm, &Nf);
9487: for (f = 0; f < Nf; ++f) {
9488: PetscFE fe, efe;
9489: PetscQuadrature q;
9490: const char *name;
9492: DMGetField(dm, f, NULL, (PetscObject *) &fe);
9493: PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9494: PetscObjectGetName((PetscObject) fe, &name);
9495: PetscObjectSetName((PetscObject) efe, name);
9496: PetscFEGetQuadrature(fe, &q);
9497: PetscFESetQuadrature(efe, q);
9498: DMSetField(edm, f, NULL, (PetscObject) efe);
9499: PetscFEDestroy(&efe);
9500: }
9501: DMCreateDS(edm);
9503: DMCreateGlobalVector(edm, errorVec);
9504: PetscObjectSetName((PetscObject) *errorVec, "Error");
9505: DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9506: DMDestroy(&edm);
9507: }
9508: PetscFree2(exactSol, ctxs);
9509: return(0);
9510: }