Actual source code: plexfem.c
1: #include <petsc/private/dmpleximpl.h>
2: #include <petscsf.h>
4: #include <petscblaslapack.h>
5: #include <petsc/private/hashsetij.h>
6: #include <petsc/private/petscfeimpl.h>
7: #include <petsc/private/petscfvimpl.h>
9: PetscBool Clementcite = PETSC_FALSE;
10: const char ClementCitation[] = "@article{clement1975approximation,\n"
11: " title = {Approximation by finite element functions using local regularization},\n"
12: " author = {Philippe Cl{\\'e}ment},\n"
13: " journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n"
14: " volume = {9},\n"
15: " number = {R2},\n"
16: " pages = {77--84},\n"
17: " year = {1975}\n}\n";
19: static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy)
20: {
21: PetscBool isPlex;
23: PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex);
24: if (isPlex) {
25: *plex = dm;
26: PetscObjectReference((PetscObject)dm);
27: } else {
28: PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex);
29: if (!*plex) {
30: DMConvert(dm, DMPLEX, plex);
31: PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex);
32: if (copy) {
33: DMSubDomainHookLink link;
35: DMCopyAuxiliaryVec(dm, *plex);
36: /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
37: for (link = dm->subdomainhook; link; link = link->next) {
38: if (link->ddhook) (*link->ddhook)(dm, *plex, link->ctx);
39: }
40: }
41: } else {
42: PetscObjectReference((PetscObject)*plex);
43: }
44: }
45: return 0;
46: }
48: static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom(void *ctx)
49: {
50: PetscFEGeom *geom = (PetscFEGeom *)ctx;
52: PetscFEGeomDestroy(&geom);
53: return 0;
54: }
56: static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
57: {
58: char composeStr[33] = {0};
59: PetscObjectId id;
60: PetscContainer container;
62: PetscObjectGetId((PetscObject)quad, &id);
63: PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id);
64: PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container);
65: if (container) {
66: PetscContainerGetPointer(container, (void **)geom);
67: } else {
68: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
69: PetscContainerCreate(PETSC_COMM_SELF, &container);
70: PetscContainerSetPointer(container, (void *)*geom);
71: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
72: PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container);
73: PetscContainerDestroy(&container);
74: }
75: return 0;
76: }
78: static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
79: {
80: *geom = NULL;
81: return 0;
82: }
84: /*@
85: DMPlexGetScale - Get the scale for the specified fundamental unit
87: Not collective
89: Input Parameters:
90: + dm - the `DM`
91: - unit - The SI unit
93: Output Parameter:
94: . scale - The value used to scale all quantities with this unit
96: Level: advanced
98: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit`
99: @*/
100: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
101: {
102: DM_Plex *mesh = (DM_Plex *)dm->data;
106: *scale = mesh->scale[unit];
107: return 0;
108: }
110: /*@
111: DMPlexSetScale - Set the scale for the specified fundamental unit
113: Not collective
115: Input Parameters:
116: + dm - the `DM`
117: . unit - The SI unit
118: - scale - The value used to scale all quantities with this unit
120: Level: advanced
122: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit`
123: @*/
124: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
125: {
126: DM_Plex *mesh = (DM_Plex *)dm->data;
129: mesh->scale[unit] = scale;
130: return 0;
131: }
133: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
134: {
135: const PetscInt eps[3][3][3] = {
136: {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}},
137: {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} },
138: {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} }
139: };
140: PetscInt *ctxInt = (PetscInt *)ctx;
141: PetscInt dim2 = ctxInt[0];
142: PetscInt d = ctxInt[1];
143: PetscInt i, j, k = dim > 2 ? d - dim : d;
146: for (i = 0; i < dim; i++) mode[i] = 0.;
147: if (d < dim) {
148: mode[d] = 1.; /* Translation along axis d */
149: } else {
150: for (i = 0; i < dim; i++) {
151: for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ }
152: }
153: }
154: return 0;
155: }
157: /*@
158: DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
160: Collective on dm
162: Input Parameters:
163: + dm - the `DM`
164: - field - The field number for the rigid body space, or 0 for the default
166: Output Parameter:
167: . sp - the null space
169: Level: advanced
171: Note:
172: This is necessary to provide a suitable coarse space for algebraic multigrid
174: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG`
175: @*/
176: PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
177: {
178: PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
179: MPI_Comm comm;
180: Vec mode[6];
181: PetscSection section, globalSection;
182: PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j;
184: PetscObjectGetComm((PetscObject)dm, &comm);
185: DMGetDimension(dm, &dim);
186: DMGetCoordinateDim(dm, &dimEmbed);
187: DMGetNumFields(dm, &Nf);
189: if (dim == 1 && Nf < 2) {
190: MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
191: return 0;
192: }
193: DMGetLocalSection(dm, §ion);
194: DMGetGlobalSection(dm, &globalSection);
195: PetscSectionGetConstrainedStorageSize(globalSection, &n);
196: PetscCalloc1(Nf, &func);
197: m = (dim * (dim + 1)) / 2;
198: VecCreate(comm, &mode[0]);
199: VecSetType(mode[0], dm->vectype);
200: VecSetSizes(mode[0], n, PETSC_DETERMINE);
201: VecSetUp(mode[0]);
202: VecGetSize(mode[0], &n);
203: mmin = PetscMin(m, n);
204: func[field] = DMPlexProjectRigidBody_Private;
205: for (i = 1; i < m; ++i) VecDuplicate(mode[0], &mode[i]);
206: for (d = 0; d < m; d++) {
207: PetscInt ctx[2];
208: void *voidctx = (void *)(&ctx[0]);
210: ctx[0] = dimEmbed;
211: ctx[1] = d;
212: DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d]);
213: }
214: /* Orthonormalize system */
215: for (i = 0; i < mmin; ++i) {
216: PetscScalar dots[6];
218: VecNormalize(mode[i], NULL);
219: VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1);
220: for (j = i + 1; j < mmin; ++j) {
221: dots[j] *= -1.0;
222: VecAXPY(mode[j], dots[j], mode[i]);
223: }
224: }
225: MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);
226: for (i = 0; i < m; ++i) VecDestroy(&mode[i]);
227: PetscFree(func);
228: return 0;
229: }
231: /*@
232: DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
234: Collective on dm
236: Input Parameters:
237: + dm - the `DM`
238: . nb - The number of bodies
239: . label - The `DMLabel` marking each domain
240: . nids - The number of ids per body
241: - ids - An array of the label ids in sequence for each domain
243: Output Parameter:
244: . sp - the null space
246: Level: advanced
248: Note:
249: This is necessary to provide a suitable coarse space for algebraic multigrid
251: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`
252: @*/
253: PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
254: {
255: MPI_Comm comm;
256: PetscSection section, globalSection;
257: Vec *mode;
258: PetscScalar *dots;
259: PetscInt dim, dimEmbed, n, m, b, d, i, j, off;
261: PetscObjectGetComm((PetscObject)dm, &comm);
262: DMGetDimension(dm, &dim);
263: DMGetCoordinateDim(dm, &dimEmbed);
264: DMGetLocalSection(dm, §ion);
265: DMGetGlobalSection(dm, &globalSection);
266: PetscSectionGetConstrainedStorageSize(globalSection, &n);
267: m = nb * (dim * (dim + 1)) / 2;
268: PetscMalloc2(m, &mode, m, &dots);
269: VecCreate(comm, &mode[0]);
270: VecSetSizes(mode[0], n, PETSC_DETERMINE);
271: VecSetUp(mode[0]);
272: for (i = 1; i < m; ++i) VecDuplicate(mode[0], &mode[i]);
273: for (b = 0, off = 0; b < nb; ++b) {
274: for (d = 0; d < m / nb; ++d) {
275: PetscInt ctx[2];
276: PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
277: void *voidctx = (void *)(&ctx[0]);
279: ctx[0] = dimEmbed;
280: ctx[1] = d;
281: DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
282: off += nids[b];
283: }
284: }
285: /* Orthonormalize system */
286: for (i = 0; i < m; ++i) {
287: PetscScalar dots[6];
289: VecNormalize(mode[i], NULL);
290: VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1);
291: for (j = i + 1; j < m; ++j) {
292: dots[j] *= -1.0;
293: VecAXPY(mode[j], dots[j], mode[i]);
294: }
295: }
296: MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
297: for (i = 0; i < m; ++i) VecDestroy(&mode[i]);
298: PetscFree2(mode, dots);
299: return 0;
300: }
302: /*@
303: DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
304: are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
305: evaluating the dual space basis of that point. A basis function is associated with the point in its
306: transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
307: projection height, which is set with this function. By default, the maximum projection height is zero, which means
308: that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior
309: basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.
311: Input Parameters:
312: + dm - the `DMPLEX` object
313: - height - the maximum projection height >= 0
315: Level: advanced
317: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
318: @*/
319: PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
320: {
321: DM_Plex *plex = (DM_Plex *)dm->data;
324: plex->maxProjectionHeight = height;
325: return 0;
326: }
328: /*@
329: DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
330: DMPlexProjectXXXLocal() functions.
332: Input Parameters:
333: . dm - the `DMPLEX` object
335: Output Parameters:
336: . height - the maximum projection height
338: Level: intermediate
340: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
341: @*/
342: PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
343: {
344: DM_Plex *plex = (DM_Plex *)dm->data;
347: *height = plex->maxProjectionHeight;
348: return 0;
349: }
351: typedef struct {
352: PetscReal alpha; /* The first Euler angle, and in 2D the only one */
353: PetscReal beta; /* The second Euler angle */
354: PetscReal gamma; /* The third Euler angle */
355: PetscInt dim; /* The dimension of R */
356: PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */
357: PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
358: } RotCtx;
360: /*
361: Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
362: we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows:
363: $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
364: $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis.
365: $ The XYZ system rotates a third time about the z axis by gamma.
366: */
367: static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
368: {
369: RotCtx *rc = (RotCtx *)ctx;
370: PetscInt dim = rc->dim;
371: PetscReal c1, s1, c2, s2, c3, s3;
373: PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT);
374: switch (dim) {
375: case 2:
376: c1 = PetscCosReal(rc->alpha);
377: s1 = PetscSinReal(rc->alpha);
378: rc->R[0] = c1;
379: rc->R[1] = s1;
380: rc->R[2] = -s1;
381: rc->R[3] = c1;
382: PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
383: DMPlex_Transpose2D_Internal(rc->RT);
384: break;
385: case 3:
386: c1 = PetscCosReal(rc->alpha);
387: s1 = PetscSinReal(rc->alpha);
388: c2 = PetscCosReal(rc->beta);
389: s2 = PetscSinReal(rc->beta);
390: c3 = PetscCosReal(rc->gamma);
391: s3 = PetscSinReal(rc->gamma);
392: rc->R[0] = c1 * c3 - c2 * s1 * s3;
393: rc->R[1] = c3 * s1 + c1 * c2 * s3;
394: rc->R[2] = s2 * s3;
395: rc->R[3] = -c1 * s3 - c2 * c3 * s1;
396: rc->R[4] = c1 * c2 * c3 - s1 * s3;
397: rc->R[5] = c3 * s2;
398: rc->R[6] = s1 * s2;
399: rc->R[7] = -c1 * s2;
400: rc->R[8] = c2;
401: PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
402: DMPlex_Transpose3D_Internal(rc->RT);
403: break;
404: default:
405: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
406: }
407: return 0;
408: }
410: static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
411: {
412: RotCtx *rc = (RotCtx *)ctx;
414: PetscFree2(rc->R, rc->RT);
415: PetscFree(rc);
416: return 0;
417: }
419: static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx)
420: {
421: RotCtx *rc = (RotCtx *)ctx;
425: if (l2g) {
426: *A = rc->R;
427: } else {
428: *A = rc->RT;
429: }
430: return 0;
431: }
433: PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx)
434: {
435: #if defined(PETSC_USE_COMPLEX)
436: switch (dim) {
437: case 2: {
438: PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0};
440: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
441: z[0] = PetscRealPart(zt[0]);
442: z[1] = PetscRealPart(zt[1]);
443: } break;
444: case 3: {
445: PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0};
447: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
448: z[0] = PetscRealPart(zt[0]);
449: z[1] = PetscRealPart(zt[1]);
450: z[2] = PetscRealPart(zt[2]);
451: } break;
452: }
453: #else
454: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx);
455: #endif
456: return 0;
457: }
459: PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
460: {
461: const PetscScalar *A;
464: (*dm->transformGetMatrix)(dm, x, l2g, &A, ctx);
465: switch (dim) {
466: case 2:
467: DMPlex_Mult2D_Internal(A, 1, y, z);
468: break;
469: case 3:
470: DMPlex_Mult3D_Internal(A, 1, y, z);
471: break;
472: }
473: return 0;
474: }
476: static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
477: {
478: PetscSection ts;
479: const PetscScalar *ta, *tva;
480: PetscInt dof;
483: DMGetLocalSection(tdm, &ts);
484: PetscSectionGetFieldDof(ts, p, f, &dof);
485: VecGetArrayRead(tv, &ta);
486: DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva);
487: if (l2g) {
488: switch (dof) {
489: case 4:
490: DMPlex_Mult2D_Internal(tva, 1, a, a);
491: break;
492: case 9:
493: DMPlex_Mult3D_Internal(tva, 1, a, a);
494: break;
495: }
496: } else {
497: switch (dof) {
498: case 4:
499: DMPlex_MultTranspose2D_Internal(tva, 1, a, a);
500: break;
501: case 9:
502: DMPlex_MultTranspose3D_Internal(tva, 1, a, a);
503: break;
504: }
505: }
506: VecRestoreArrayRead(tv, &ta);
507: return 0;
508: }
510: static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a)
511: {
512: PetscSection s, ts;
513: const PetscScalar *ta, *tvaf, *tvag;
514: PetscInt fdof, gdof, fpdof, gpdof;
517: DMGetLocalSection(dm, &s);
518: DMGetLocalSection(tdm, &ts);
519: PetscSectionGetFieldDof(s, pf, f, &fpdof);
520: PetscSectionGetFieldDof(s, pg, g, &gpdof);
521: PetscSectionGetFieldDof(ts, pf, f, &fdof);
522: PetscSectionGetFieldDof(ts, pg, g, &gdof);
523: VecGetArrayRead(tv, &ta);
524: DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf);
525: DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag);
526: if (l2g) {
527: switch (fdof) {
528: case 4:
529: DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);
530: break;
531: case 9:
532: DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);
533: break;
534: }
535: switch (gdof) {
536: case 4:
537: DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);
538: break;
539: case 9:
540: DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);
541: break;
542: }
543: } else {
544: switch (fdof) {
545: case 4:
546: DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);
547: break;
548: case 9:
549: DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);
550: break;
551: }
552: switch (gdof) {
553: case 4:
554: DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);
555: break;
556: case 9:
557: DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);
558: break;
559: }
560: }
561: VecRestoreArrayRead(tv, &ta);
562: return 0;
563: }
565: PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
566: {
567: PetscSection s;
568: PetscSection clSection;
569: IS clPoints;
570: const PetscInt *clp;
571: PetscInt *points = NULL;
572: PetscInt Nf, f, Np, cp, dof, d = 0;
574: DMGetLocalSection(dm, &s);
575: PetscSectionGetNumFields(s, &Nf);
576: DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
577: for (f = 0; f < Nf; ++f) {
578: for (cp = 0; cp < Np * 2; cp += 2) {
579: PetscSectionGetFieldDof(s, points[cp], f, &dof);
580: if (!dof) continue;
581: if (fieldActive[f]) DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]);
582: d += dof;
583: }
584: }
585: DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
586: return 0;
587: }
589: PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
590: {
591: PetscSection s;
592: PetscSection clSection;
593: IS clPoints;
594: const PetscInt *clp;
595: PetscInt *points = NULL;
596: PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
598: DMGetLocalSection(dm, &s);
599: PetscSectionGetNumFields(s, &Nf);
600: DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
601: for (f = 0, r = 0; f < Nf; ++f) {
602: for (cpf = 0; cpf < Np * 2; cpf += 2) {
603: PetscSectionGetFieldDof(s, points[cpf], f, &fdof);
604: for (g = 0, c = 0; g < Nf; ++g) {
605: for (cpg = 0; cpg < Np * 2; cpg += 2) {
606: PetscSectionGetFieldDof(s, points[cpg], g, &gdof);
607: DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c]);
608: c += gdof;
609: }
610: }
612: r += fdof;
613: }
614: }
616: DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
617: return 0;
618: }
620: static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
621: {
622: DM tdm;
623: Vec tv;
624: PetscSection ts, s;
625: const PetscScalar *ta;
626: PetscScalar *a, *va;
627: PetscInt pStart, pEnd, p, Nf, f;
629: DMGetBasisTransformDM_Internal(dm, &tdm);
630: DMGetBasisTransformVec_Internal(dm, &tv);
631: DMGetLocalSection(tdm, &ts);
632: DMGetLocalSection(dm, &s);
633: PetscSectionGetChart(s, &pStart, &pEnd);
634: PetscSectionGetNumFields(s, &Nf);
635: VecGetArray(lv, &a);
636: VecGetArrayRead(tv, &ta);
637: for (p = pStart; p < pEnd; ++p) {
638: for (f = 0; f < Nf; ++f) {
639: DMPlexPointLocalFieldRef(dm, p, f, a, &va);
640: DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va);
641: }
642: }
643: VecRestoreArray(lv, &a);
644: VecRestoreArrayRead(tv, &ta);
645: return 0;
646: }
648: /*@
649: DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis
651: Input Parameters:
652: + dm - The `DM`
653: - lv - A local vector with values in the global basis
655: Output Parameters:
656: . lv - A local vector with values in the local basis
658: Level: developer
660: Note:
661: This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user will have a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal.
663: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
664: @*/
665: PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
666: {
669: DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE);
670: return 0;
671: }
673: /*@
674: DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis
676: Input Parameters:
677: + dm - The `DM`
678: - lv - A local vector with values in the local basis
680: Output Parameters:
681: . lv - A local vector with values in the global basis
683: Level: developer
685: Note:
686: This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user would want a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal.
688: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
689: @*/
690: PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
691: {
694: DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE);
695: return 0;
696: }
698: /*@
699: DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
700: and global solutions, to a local basis, appropriate for discretization integrals and assembly.
702: Input Parameters:
703: + dm - The `DM`
704: . alpha - The first Euler angle, and in 2D the only one
705: . beta - The second Euler angle
706: - gamma - The third Euler angle
708: Level: developer
710: Note:
711: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
712: we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows
713: .vb
714: The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
715: The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis.
716: The XYZ system rotates a third time about the z axis by gamma.
717: .ve
719: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`
720: @*/
721: PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
722: {
723: RotCtx *rc;
724: PetscInt cdim;
726: DMGetCoordinateDim(dm, &cdim);
727: PetscMalloc1(1, &rc);
728: dm->transformCtx = rc;
729: dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal;
730: dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal;
731: dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
732: rc->dim = cdim;
733: rc->alpha = alpha;
734: rc->beta = beta;
735: rc->gamma = gamma;
736: (*dm->transformSetUp)(dm, dm->transformCtx);
737: DMConstructBasisTransform_Internal(dm);
738: return 0;
739: }
741: /*@C
742: DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates
744: Input Parameters:
745: + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
746: . time - The time
747: . field - The field to constrain
748: . Nc - The number of constrained field components, or 0 for all components
749: . comps - An array of constrained component numbers, or NULL for all components
750: . label - The `DMLabel` defining constrained points
751: . numids - The number of `DMLabel` ids for constrained points
752: . ids - An array of ids for constrained points
753: . func - A pointwise function giving boundary values
754: - ctx - An optional user context for bcFunc
756: Output Parameter:
757: . locX - A local vector to receives the boundary values
759: Level: developer
761: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
762: @*/
763: PetscErrorCode DMPlexInsertBoundaryValuesEssential(DM dm, PetscReal time, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX)
764: {
765: PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
766: void **ctxs;
767: PetscInt numFields;
769: DMGetNumFields(dm, &numFields);
770: PetscCalloc2(numFields, &funcs, numFields, &ctxs);
771: funcs[field] = func;
772: ctxs[field] = ctx;
773: DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
774: PetscFree2(funcs, ctxs);
775: return 0;
776: }
778: /*@C
779: DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data
781: Input Parameters:
782: + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
783: . time - The time
784: . locU - A local vector with the input solution values
785: . field - The field to constrain
786: . Nc - The number of constrained field components, or 0 for all components
787: . comps - An array of constrained component numbers, or NULL for all components
788: . label - The `DMLabel` defining constrained points
789: . numids - The number of `DMLabel` ids for constrained points
790: . ids - An array of ids for constrained points
791: . func - A pointwise function giving boundary values
792: - ctx - An optional user context for bcFunc
794: Output Parameter:
795: . locX - A local vector to receives the boundary values
797: Level: developer
799: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
800: @*/
801: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX)
802: {
803: void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
804: void **ctxs;
805: PetscInt numFields;
807: DMGetNumFields(dm, &numFields);
808: PetscCalloc2(numFields, &funcs, numFields, &ctxs);
809: funcs[field] = func;
810: ctxs[field] = ctx;
811: DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
812: PetscFree2(funcs, ctxs);
813: return 0;
814: }
816: /*@C
817: DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data
819: Collective on dm
821: Input Parameters:
822: + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
823: . time - The time
824: . locU - A local vector with the input solution values
825: . field - The field to constrain
826: . Nc - The number of constrained field components, or 0 for all components
827: . comps - An array of constrained component numbers, or NULL for all components
828: . label - The `DMLabel` defining constrained points
829: . numids - The number of `DMLabel` ids for constrained points
830: . ids - An array of ids for constrained points
831: . func - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal()
832: - ctx - An optional user context for bcFunc
834: Output Parameter:
835: . locX - A local vector to receive the boundary values
837: Level: developer
839: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
840: @*/
841: PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX)
842: {
843: void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
844: void **ctxs;
845: PetscInt numFields;
847: DMGetNumFields(dm, &numFields);
848: PetscCalloc2(numFields, &funcs, numFields, &ctxs);
849: funcs[field] = func;
850: ctxs[field] = ctx;
851: DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
852: PetscFree2(funcs, ctxs);
853: return 0;
854: }
856: /*@C
857: DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
859: Input Parameters:
860: + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
861: . time - The time
862: . faceGeometry - A vector with the FVM face geometry information
863: . cellGeometry - A vector with the FVM cell geometry information
864: . Grad - A vector with the FVM cell gradient information
865: . field - The field to constrain
866: . Nc - The number of constrained field components, or 0 for all components
867: . comps - An array of constrained component numbers, or NULL for all components
868: . label - The `DMLabel` defining constrained points
869: . numids - The number of `DMLabel` ids for constrained points
870: . ids - An array of ids for constrained points
871: . func - A pointwise function giving boundary values
872: - ctx - An optional user context for bcFunc
874: Output Parameter:
875: . locX - A local vector to receives the boundary values
877: Level: developer
879: Note:
880: This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()`
882: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
883: @*/
884: PetscErrorCode DMPlexInsertBoundaryValuesRiemann(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *), void *ctx, Vec locX)
885: {
886: PetscDS prob;
887: PetscSF sf;
888: DM dmFace, dmCell, dmGrad;
889: const PetscScalar *facegeom, *cellgeom = NULL, *grad;
890: const PetscInt *leaves;
891: PetscScalar *x, *fx;
892: PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i;
893: PetscErrorCode ierru = 0;
895: DMGetPointSF(dm, &sf);
896: PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
897: nleaves = PetscMax(0, nleaves);
898: DMGetDimension(dm, &dim);
899: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
900: DMGetDS(dm, &prob);
901: VecGetDM(faceGeometry, &dmFace);
902: VecGetArrayRead(faceGeometry, &facegeom);
903: if (cellGeometry) {
904: VecGetDM(cellGeometry, &dmCell);
905: VecGetArrayRead(cellGeometry, &cellgeom);
906: }
907: if (Grad) {
908: PetscFV fv;
910: PetscDSGetDiscretization(prob, field, (PetscObject *)&fv);
911: VecGetDM(Grad, &dmGrad);
912: VecGetArrayRead(Grad, &grad);
913: PetscFVGetNumComponents(fv, &pdim);
914: DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
915: }
916: VecGetArray(locX, &x);
917: for (i = 0; i < numids; ++i) {
918: IS faceIS;
919: const PetscInt *faces;
920: PetscInt numFaces, f;
922: DMLabelGetStratumIS(label, ids[i], &faceIS);
923: if (!faceIS) continue; /* No points with that id on this process */
924: ISGetLocalSize(faceIS, &numFaces);
925: ISGetIndices(faceIS, &faces);
926: for (f = 0; f < numFaces; ++f) {
927: const PetscInt face = faces[f], *cells;
928: PetscFVFaceGeom *fg;
930: if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
931: PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc);
932: if (loc >= 0) continue;
933: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
934: DMPlexGetSupport(dm, face, &cells);
935: if (Grad) {
936: PetscFVCellGeom *cg;
937: PetscScalar *cx, *cgrad;
938: PetscScalar *xG;
939: PetscReal dx[3];
940: PetscInt d;
942: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);
943: DMPlexPointLocalRead(dm, cells[0], x, &cx);
944: DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);
945: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
946: DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
947: for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx);
948: (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);
949: } else {
950: PetscScalar *xI;
951: PetscScalar *xG;
953: DMPlexPointLocalRead(dm, cells[0], x, &xI);
954: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
955: ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
956: if (ierru) {
957: ISRestoreIndices(faceIS, &faces);
958: ISDestroy(&faceIS);
959: goto cleanup;
960: }
961: }
962: }
963: ISRestoreIndices(faceIS, &faces);
964: ISDestroy(&faceIS);
965: }
966: cleanup:
967: VecRestoreArray(locX, &x);
968: if (Grad) {
969: DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);
970: VecRestoreArrayRead(Grad, &grad);
971: }
972: if (cellGeometry) VecRestoreArrayRead(cellGeometry, &cellgeom);
973: VecRestoreArrayRead(faceGeometry, &facegeom);
974: ierru;
975: return 0;
976: }
978: static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
979: {
980: PetscInt c;
981: for (c = 0; c < Nc; ++c) u[c] = 0.0;
982: return 0;
983: }
985: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
986: {
987: PetscObject isZero;
988: PetscDS prob;
989: PetscInt numBd, b;
991: DMGetDS(dm, &prob);
992: PetscDSGetNumBoundary(prob, &numBd);
993: PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero);
994: for (b = 0; b < numBd; ++b) {
995: PetscWeakForm wf;
996: DMBoundaryConditionType type;
997: const char *name;
998: DMLabel label;
999: PetscInt field, Nc;
1000: const PetscInt *comps;
1001: PetscObject obj;
1002: PetscClassId id;
1003: void (*bvfunc)(void);
1004: PetscInt numids;
1005: const PetscInt *ids;
1006: void *ctx;
1008: PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx);
1009: if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1010: DMGetField(dm, field, NULL, &obj);
1011: PetscObjectGetClassId(obj, &id);
1012: if (id == PETSCFE_CLASSID) {
1013: switch (type) {
1014: /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1015: case DM_BC_ESSENTIAL: {
1016: PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc;
1018: if (isZero) func = zero;
1019: DMPlexLabelAddCells(dm, label);
1020: DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX);
1021: DMPlexLabelClearCells(dm, label);
1022: } break;
1023: case DM_BC_ESSENTIAL_FIELD: {
1024: PetscPointFunc func = (PetscPointFunc)bvfunc;
1026: DMPlexLabelAddCells(dm, label);
1027: DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX);
1028: DMPlexLabelClearCells(dm, label);
1029: } break;
1030: default:
1031: break;
1032: }
1033: } else if (id == PETSCFV_CLASSID) {
1034: {
1035: PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc;
1037: if (!faceGeomFVM) continue;
1038: DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX);
1039: }
1040: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1041: }
1042: return 0;
1043: }
1045: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1046: {
1047: PetscObject isZero;
1048: PetscDS prob;
1049: PetscInt numBd, b;
1051: if (!locX) return 0;
1052: DMGetDS(dm, &prob);
1053: PetscDSGetNumBoundary(prob, &numBd);
1054: PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero);
1055: for (b = 0; b < numBd; ++b) {
1056: PetscWeakForm wf;
1057: DMBoundaryConditionType type;
1058: const char *name;
1059: DMLabel label;
1060: PetscInt field, Nc;
1061: const PetscInt *comps;
1062: PetscObject obj;
1063: PetscClassId id;
1064: PetscInt numids;
1065: const PetscInt *ids;
1066: void (*bvfunc)(void);
1067: void *ctx;
1069: PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx);
1070: if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1071: DMGetField(dm, field, NULL, &obj);
1072: PetscObjectGetClassId(obj, &id);
1073: if (id == PETSCFE_CLASSID) {
1074: switch (type) {
1075: /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1076: case DM_BC_ESSENTIAL: {
1077: PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc;
1079: if (isZero) func_t = zero;
1080: DMPlexLabelAddCells(dm, label);
1081: DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX);
1082: DMPlexLabelClearCells(dm, label);
1083: } break;
1084: case DM_BC_ESSENTIAL_FIELD: {
1085: PetscPointFunc func_t = (PetscPointFunc)bvfunc;
1087: DMPlexLabelAddCells(dm, label);
1088: DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX);
1089: DMPlexLabelClearCells(dm, label);
1090: } break;
1091: default:
1092: break;
1093: }
1094: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1095: }
1096: return 0;
1097: }
1099: /*@
1100: DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
1102: Not Collective
1104: Input Parameters:
1105: + dm - The `DM`
1106: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1107: . time - The time
1108: . faceGeomFVM - Face geometry data for FV discretizations
1109: . cellGeomFVM - Cell geometry data for FV discretizations
1110: - gradFVM - Gradient reconstruction data for FV discretizations
1112: Output Parameters:
1113: . locX - Solution updated with boundary values
1115: Level: intermediate
1117: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()`
1118: @*/
1119: PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1120: {
1126: PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM));
1127: return 0;
1128: }
1130: /*@
1131: DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector
1133: Input Parameters:
1134: + dm - The `DM`
1135: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1136: . time - The time
1137: . faceGeomFVM - Face geometry data for FV discretizations
1138: . cellGeomFVM - Cell geometry data for FV discretizations
1139: - gradFVM - Gradient reconstruction data for FV discretizations
1141: Output Parameters:
1142: . locX_t - Solution updated with boundary values
1144: Level: developer
1146: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`
1147: @*/
1148: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1149: {
1155: PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM));
1156: return 0;
1157: }
1159: PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1160: {
1161: Vec localX;
1163: DMGetLocalVector(dm, &localX);
1164: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);
1165: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1166: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1167: DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);
1168: DMRestoreLocalVector(dm, &localX);
1169: return 0;
1170: }
1172: /*@C
1173: DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
1175: Collective on dm
1177: Input Parameters:
1178: + dm - The `DM`
1179: . time - The time
1180: . funcs - The functions to evaluate for each field component
1181: . ctxs - Optional array of contexts to pass to each function, or NULL.
1182: - localX - The coefficient vector u_h, a local vector
1184: Output Parameter:
1185: . diff - The diff ||u - u_h||_2
1187: Level: developer
1189: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1190: @*/
1191: PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1192: {
1193: const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1194: DM tdm;
1195: Vec tv;
1196: PetscSection section;
1197: PetscQuadrature quad;
1198: PetscFEGeom fegeom;
1199: PetscScalar *funcVal, *interpolant;
1200: PetscReal *coords, *gcoords;
1201: PetscReal localDiff = 0.0;
1202: const PetscReal *quadWeights;
1203: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1204: PetscBool transform;
1206: DMGetDimension(dm, &dim);
1207: DMGetCoordinateDim(dm, &coordDim);
1208: fegeom.dimEmbed = coordDim;
1209: DMGetLocalSection(dm, §ion);
1210: PetscSectionGetNumFields(section, &numFields);
1211: DMGetBasisTransformDM_Internal(dm, &tdm);
1212: DMGetBasisTransformVec_Internal(dm, &tv);
1213: DMHasBasisTransform(dm, &transform);
1214: for (field = 0; field < numFields; ++field) {
1215: PetscObject obj;
1216: PetscClassId id;
1217: PetscInt Nc;
1219: DMGetField(dm, field, NULL, &obj);
1220: PetscObjectGetClassId(obj, &id);
1221: if (id == PETSCFE_CLASSID) {
1222: PetscFE fe = (PetscFE)obj;
1224: PetscFEGetQuadrature(fe, &quad);
1225: PetscFEGetNumComponents(fe, &Nc);
1226: } else if (id == PETSCFV_CLASSID) {
1227: PetscFV fv = (PetscFV)obj;
1229: PetscFVGetQuadrature(fv, &quad);
1230: PetscFVGetNumComponents(fv, &Nc);
1231: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1232: numComponents += Nc;
1233: }
1234: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1236: PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ);
1237: DMPlexGetVTKCellHeight(dm, &cellHeight);
1238: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
1239: for (c = cStart; c < cEnd; ++c) {
1240: PetscScalar *x = NULL;
1241: PetscReal elemDiff = 0.0;
1242: PetscInt qc = 0;
1244: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1245: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1247: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1248: PetscObject obj;
1249: PetscClassId id;
1250: void *const ctx = ctxs ? ctxs[field] : NULL;
1251: PetscInt Nb, Nc, q, fc;
1253: DMGetField(dm, field, NULL, &obj);
1254: PetscObjectGetClassId(obj, &id);
1255: if (id == PETSCFE_CLASSID) {
1256: PetscFEGetNumComponents((PetscFE)obj, &Nc);
1257: PetscFEGetDimension((PetscFE)obj, &Nb);
1258: } else if (id == PETSCFV_CLASSID) {
1259: PetscFVGetNumComponents((PetscFV)obj, &Nc);
1260: Nb = 1;
1261: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1262: if (debug) {
1263: char title[1024];
1264: PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field);
1265: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1266: }
1267: for (q = 0; q < Nq; ++q) {
1268: PetscFEGeom qgeom;
1271: qgeom.dimEmbed = fegeom.dimEmbed;
1272: qgeom.J = &fegeom.J[q * coordDim * coordDim];
1273: qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim];
1274: qgeom.detJ = &fegeom.detJ[q];
1276: if (transform) {
1277: gcoords = &coords[coordDim * Nq];
1278: DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx);
1279: } else {
1280: gcoords = &coords[coordDim * q];
1281: }
1282: PetscArrayzero(funcVal, Nc);
1283: (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1284: if (ierr) {
1285: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1286: DMRestoreLocalVector(dm, &localX);
1287: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1288: }
1289: if (transform) DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);
1290: if (id == PETSCFE_CLASSID) PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant);
1291: else if (id == PETSCFV_CLASSID) PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant);
1292: else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1293: for (fc = 0; fc < Nc; ++fc) {
1294: const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
1295: if (debug)
1296: PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g (%g, %g)\n", c, field, fc, (double)(coordDim > 0 ? coords[coordDim * q] : 0.), (double)(coordDim > 1 ? coords[coordDim * q + 1] : 0.), (double)(coordDim > 2 ? coords[coordDim * q + 2] : 0.),
1297: (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc])));
1298: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1299: }
1300: }
1301: fieldOffset += Nb;
1302: qc += Nc;
1303: }
1304: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1305: if (debug) PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff);
1306: localDiff += elemDiff;
1307: }
1308: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1309: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1310: *diff = PetscSqrtReal(*diff);
1311: return 0;
1312: }
1314: PetscErrorCode DMComputeL2GradientDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
1315: {
1316: const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1317: DM tdm;
1318: PetscSection section;
1319: PetscQuadrature quad;
1320: Vec localX, tv;
1321: PetscScalar *funcVal, *interpolant;
1322: const PetscReal *quadWeights;
1323: PetscFEGeom fegeom;
1324: PetscReal *coords, *gcoords;
1325: PetscReal localDiff = 0.0;
1326: PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1327: PetscBool transform;
1329: DMGetDimension(dm, &dim);
1330: DMGetCoordinateDim(dm, &coordDim);
1331: fegeom.dimEmbed = coordDim;
1332: DMGetLocalSection(dm, §ion);
1333: PetscSectionGetNumFields(section, &numFields);
1334: DMGetLocalVector(dm, &localX);
1335: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1336: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1337: DMGetBasisTransformDM_Internal(dm, &tdm);
1338: DMGetBasisTransformVec_Internal(dm, &tv);
1339: DMHasBasisTransform(dm, &transform);
1340: for (field = 0; field < numFields; ++field) {
1341: PetscFE fe;
1342: PetscInt Nc;
1344: DMGetField(dm, field, NULL, (PetscObject *)&fe);
1345: PetscFEGetQuadrature(fe, &quad);
1346: PetscFEGetNumComponents(fe, &Nc);
1347: numComponents += Nc;
1348: }
1349: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1351: /* DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
1352: PetscMalloc6(numComponents, &funcVal, coordDim * Nq, &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ);
1353: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1354: for (c = cStart; c < cEnd; ++c) {
1355: PetscScalar *x = NULL;
1356: PetscReal elemDiff = 0.0;
1357: PetscInt qc = 0;
1359: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1360: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1362: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1363: PetscFE fe;
1364: void *const ctx = ctxs ? ctxs[field] : NULL;
1365: PetscInt Nb, Nc, q, fc;
1367: DMGetField(dm, field, NULL, (PetscObject *)&fe);
1368: PetscFEGetDimension(fe, &Nb);
1369: PetscFEGetNumComponents(fe, &Nc);
1370: if (debug) {
1371: char title[1024];
1372: PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field);
1373: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1374: }
1375: for (q = 0; q < Nq; ++q) {
1376: PetscFEGeom qgeom;
1379: qgeom.dimEmbed = fegeom.dimEmbed;
1380: qgeom.J = &fegeom.J[q * coordDim * coordDim];
1381: qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim];
1382: qgeom.detJ = &fegeom.detJ[q];
1384: if (transform) {
1385: gcoords = &coords[coordDim * Nq];
1386: DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx);
1387: } else {
1388: gcoords = &coords[coordDim * q];
1389: }
1390: PetscArrayzero(funcVal, Nc);
1391: (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1392: if (ierr) {
1393: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1394: DMRestoreLocalVector(dm, &localX);
1395: PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ);
1396: }
1397: if (transform) DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);
1398: PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant);
1399: /* Overwrite with the dot product if the normal is given */
1400: if (n) {
1401: for (fc = 0; fc < Nc; ++fc) {
1402: PetscScalar sum = 0.0;
1403: PetscInt d;
1404: for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d];
1405: interpolant[fc] = sum;
1406: }
1407: }
1408: for (fc = 0; fc < Nc; ++fc) {
1409: const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
1410: if (debug) PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " fieldDer %" PetscInt_FMT ",%" PetscInt_FMT " diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]));
1411: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1412: }
1413: }
1414: fieldOffset += Nb;
1415: qc += Nc;
1416: }
1417: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1418: if (debug) PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff);
1419: localDiff += elemDiff;
1420: }
1421: PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ);
1422: DMRestoreLocalVector(dm, &localX);
1423: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1424: *diff = PetscSqrtReal(*diff);
1425: return 0;
1426: }
1428: PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1429: {
1430: const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1431: DM tdm;
1432: DMLabel depthLabel;
1433: PetscSection section;
1434: Vec localX, tv;
1435: PetscReal *localDiff;
1436: PetscInt dim, depth, dE, Nf, f, Nds, s;
1437: PetscBool transform;
1439: DMGetDimension(dm, &dim);
1440: DMGetCoordinateDim(dm, &dE);
1441: DMGetLocalSection(dm, §ion);
1442: DMGetLocalVector(dm, &localX);
1443: DMGetBasisTransformDM_Internal(dm, &tdm);
1444: DMGetBasisTransformVec_Internal(dm, &tv);
1445: DMHasBasisTransform(dm, &transform);
1446: DMGetNumFields(dm, &Nf);
1447: DMPlexGetDepthLabel(dm, &depthLabel);
1448: DMLabelGetNumValues(depthLabel, &depth);
1450: VecSet(localX, 0.0);
1451: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1452: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1453: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1454: DMGetNumDS(dm, &Nds);
1455: PetscCalloc1(Nf, &localDiff);
1456: for (s = 0; s < Nds; ++s) {
1457: PetscDS ds;
1458: DMLabel label;
1459: IS fieldIS, pointIS;
1460: const PetscInt *fields, *points = NULL;
1461: PetscQuadrature quad;
1462: const PetscReal *quadPoints, *quadWeights;
1463: PetscFEGeom fegeom;
1464: PetscReal *coords, *gcoords;
1465: PetscScalar *funcVal, *interpolant;
1466: PetscBool isCohesive;
1467: PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;
1469: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
1470: ISGetIndices(fieldIS, &fields);
1471: PetscDSIsCohesive(ds, &isCohesive);
1472: PetscDSGetNumFields(ds, &dsNf);
1473: PetscDSGetTotalComponents(ds, &totNc);
1474: PetscDSGetQuadrature(ds, &quad);
1475: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1477: PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ);
1478: if (!label) {
1479: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1480: } else {
1481: DMLabelGetStratumIS(label, 1, &pointIS);
1482: ISGetLocalSize(pointIS, &cEnd);
1483: ISGetIndices(pointIS, &points);
1484: }
1485: for (c = cStart; c < cEnd; ++c) {
1486: const PetscInt cell = points ? points[c] : c;
1487: PetscScalar *x = NULL;
1488: const PetscInt *cone;
1489: PetscInt qc = 0, fOff = 0, dep;
1491: DMLabelGetValue(depthLabel, cell, &dep);
1492: if (dep != depth - 1) continue;
1493: if (isCohesive) {
1494: DMPlexGetCone(dm, cell, &cone);
1495: DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1496: } else {
1497: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1498: }
1499: DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x);
1500: for (f = 0; f < dsNf; ++f) {
1501: PetscObject obj;
1502: PetscClassId id;
1503: void *const ctx = ctxs ? ctxs[fields[f]] : NULL;
1504: PetscInt Nb, Nc, q, fc;
1505: PetscReal elemDiff = 0.0;
1506: PetscBool cohesive;
1508: PetscDSGetCohesive(ds, f, &cohesive);
1509: if (isCohesive && !cohesive) continue;
1510: PetscDSGetDiscretization(ds, f, &obj);
1511: PetscObjectGetClassId(obj, &id);
1512: if (id == PETSCFE_CLASSID) {
1513: PetscFEGetNumComponents((PetscFE)obj, &Nc);
1514: PetscFEGetDimension((PetscFE)obj, &Nb);
1515: } else if (id == PETSCFV_CLASSID) {
1516: PetscFVGetNumComponents((PetscFV)obj, &Nc);
1517: Nb = 1;
1518: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
1519: if (debug) {
1520: char title[1024];
1521: PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f]);
1522: DMPrintCellVector(cell, title, Nb, &x[fOff]);
1523: }
1524: for (q = 0; q < Nq; ++q) {
1525: PetscFEGeom qgeom;
1528: qgeom.dimEmbed = fegeom.dimEmbed;
1529: qgeom.J = &fegeom.J[q * dE * dE];
1530: qgeom.invJ = &fegeom.invJ[q * dE * dE];
1531: qgeom.detJ = &fegeom.detJ[q];
1533: if (transform) {
1534: gcoords = &coords[dE * Nq];
1535: DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx);
1536: } else {
1537: gcoords = &coords[dE * q];
1538: }
1539: for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.;
1540: (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1541: if (ierr) {
1542: DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);
1543: DMRestoreLocalVector(dm, &localX);
1544: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1545: }
1546: if (transform) DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);
1547: /* Call once for each face, except for lagrange field */
1548: if (id == PETSCFE_CLASSID) PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant);
1549: else if (id == PETSCFV_CLASSID) PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant);
1550: else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
1551: for (fc = 0; fc < Nc; ++fc) {
1552: const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
1553: if (debug)
1554: PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g\n", cell, fields[f], fc, (double)(dE > 0 ? coords[dE * q] : 0.), (double)(dE > 1 ? coords[dE * q + 1] : 0.), (double)(dE > 2 ? coords[dE * q + 2] : 0.),
1555: (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q])));
1556: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1557: }
1558: }
1559: fOff += Nb;
1560: qc += Nc;
1561: localDiff[fields[f]] += elemDiff;
1562: if (debug) PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT " cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]]);
1563: }
1564: DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);
1565: }
1566: if (label) {
1567: ISRestoreIndices(pointIS, &points);
1568: ISDestroy(&pointIS);
1569: }
1570: ISRestoreIndices(fieldIS, &fields);
1571: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1572: }
1573: DMRestoreLocalVector(dm, &localX);
1574: MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1575: PetscFree(localDiff);
1576: for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
1577: return 0;
1578: }
1580: /*@C
1581: DMPlexComputeL2DiffVec - This function computes the cellwise L_2 difference between a function u and an FEM interpolant solution u_h, and stores it in a Vec.
1583: Collective on dm
1585: Input Parameters:
1586: + dm - The `DM`
1587: . time - The time
1588: . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
1589: . ctxs - Optional array of contexts to pass to each function, or NULL.
1590: - X - The coefficient vector u_h
1592: Output Parameter:
1593: . D - A Vec which holds the difference ||u - u_h||_2 for each cell
1595: Level: developer
1597: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1598: @*/
1599: PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1600: {
1601: PetscSection section;
1602: PetscQuadrature quad;
1603: Vec localX;
1604: PetscFEGeom fegeom;
1605: PetscScalar *funcVal, *interpolant;
1606: PetscReal *coords;
1607: const PetscReal *quadPoints, *quadWeights;
1608: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1610: VecSet(D, 0.0);
1611: DMGetDimension(dm, &dim);
1612: DMGetCoordinateDim(dm, &coordDim);
1613: DMGetLocalSection(dm, §ion);
1614: PetscSectionGetNumFields(section, &numFields);
1615: DMGetLocalVector(dm, &localX);
1616: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1617: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1618: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1619: for (field = 0; field < numFields; ++field) {
1620: PetscObject obj;
1621: PetscClassId id;
1622: PetscInt Nc;
1624: DMGetField(dm, field, NULL, &obj);
1625: PetscObjectGetClassId(obj, &id);
1626: if (id == PETSCFE_CLASSID) {
1627: PetscFE fe = (PetscFE)obj;
1629: PetscFEGetQuadrature(fe, &quad);
1630: PetscFEGetNumComponents(fe, &Nc);
1631: } else if (id == PETSCFV_CLASSID) {
1632: PetscFV fv = (PetscFV)obj;
1634: PetscFVGetQuadrature(fv, &quad);
1635: PetscFVGetNumComponents(fv, &Nc);
1636: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1637: numComponents += Nc;
1638: }
1639: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1641: PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ);
1642: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1643: for (c = cStart; c < cEnd; ++c) {
1644: PetscScalar *x = NULL;
1645: PetscScalar elemDiff = 0.0;
1646: PetscInt qc = 0;
1648: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1649: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1651: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1652: PetscObject obj;
1653: PetscClassId id;
1654: void *const ctx = ctxs ? ctxs[field] : NULL;
1655: PetscInt Nb, Nc, q, fc;
1657: DMGetField(dm, field, NULL, &obj);
1658: PetscObjectGetClassId(obj, &id);
1659: if (id == PETSCFE_CLASSID) {
1660: PetscFEGetNumComponents((PetscFE)obj, &Nc);
1661: PetscFEGetDimension((PetscFE)obj, &Nb);
1662: } else if (id == PETSCFV_CLASSID) {
1663: PetscFVGetNumComponents((PetscFV)obj, &Nc);
1664: Nb = 1;
1665: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1666: if (funcs[field]) {
1667: for (q = 0; q < Nq; ++q) {
1668: PetscFEGeom qgeom;
1670: qgeom.dimEmbed = fegeom.dimEmbed;
1671: qgeom.J = &fegeom.J[q * coordDim * coordDim];
1672: qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim];
1673: qgeom.detJ = &fegeom.detJ[q];
1675: (*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx);
1676: #if defined(needs_fix_with_return_code_argument)
1677: if (ierr) {
1678: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1679: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1680: DMRestoreLocalVector(dm, &localX);
1681: }
1682: #endif
1683: if (id == PETSCFE_CLASSID) PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant);
1684: else if (id == PETSCFV_CLASSID) PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant);
1685: else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1686: for (fc = 0; fc < Nc; ++fc) {
1687: const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
1688: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1689: }
1690: }
1691: }
1692: fieldOffset += Nb;
1693: qc += Nc;
1694: }
1695: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1696: VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);
1697: }
1698: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1699: DMRestoreLocalVector(dm, &localX);
1700: VecSqrtAbs(D);
1701: return 0;
1702: }
1704: /*@
1705: DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1, and stores it in a Vec.
1707: Collective on dm
1709: Input Parameters:
1710: + dm - The `DM`
1711: - locX - The coefficient vector u_h
1713: Output Parameter:
1714: . locC - A `Vec` which holds the Clement interpolant of the function
1716: Level: developer
1718: Note:
1719: $ u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume
1721: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1722: @*/
1723: PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC)
1724: {
1725: PetscInt debug = ((DM_Plex *)dm->data)->printFEM;
1726: DM dmc;
1727: PetscQuadrature quad;
1728: PetscScalar *interpolant, *valsum;
1729: PetscFEGeom fegeom;
1730: PetscReal *coords;
1731: const PetscReal *quadPoints, *quadWeights;
1732: PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v;
1734: PetscCitationsRegister(ClementCitation, &Clementcite);
1735: VecGetDM(locC, &dmc);
1736: VecSet(locC, 0.0);
1737: DMGetDimension(dm, &dim);
1738: DMGetCoordinateDim(dm, &cdim);
1739: fegeom.dimEmbed = cdim;
1740: DMGetNumFields(dm, &Nf);
1742: for (f = 0; f < Nf; ++f) {
1743: PetscObject obj;
1744: PetscClassId id;
1745: PetscInt fNc;
1747: DMGetField(dm, f, NULL, &obj);
1748: PetscObjectGetClassId(obj, &id);
1749: if (id == PETSCFE_CLASSID) {
1750: PetscFE fe = (PetscFE)obj;
1752: PetscFEGetQuadrature(fe, &quad);
1753: PetscFEGetNumComponents(fe, &fNc);
1754: } else if (id == PETSCFV_CLASSID) {
1755: PetscFV fv = (PetscFV)obj;
1757: PetscFVGetQuadrature(fv, &quad);
1758: PetscFVGetNumComponents(fv, &fNc);
1759: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
1760: Nc += fNc;
1761: }
1762: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1764: PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ);
1765: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1766: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1767: for (v = vStart; v < vEnd; ++v) {
1768: PetscScalar volsum = 0.0;
1769: PetscInt *star = NULL;
1770: PetscInt starSize, st, fc;
1772: PetscArrayzero(valsum, Nc);
1773: DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1774: for (st = 0; st < starSize * 2; st += 2) {
1775: const PetscInt cell = star[st];
1776: PetscScalar *val = &valsum[Nc];
1777: PetscScalar *x = NULL;
1778: PetscReal vol = 0.0;
1779: PetscInt foff = 0;
1781: if ((cell < cStart) || (cell >= cEnd)) continue;
1782: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1783: DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1784: for (f = 0; f < Nf; ++f) {
1785: PetscObject obj;
1786: PetscClassId id;
1787: PetscInt Nb, fNc, q;
1789: PetscArrayzero(val, Nc);
1790: DMGetField(dm, f, NULL, &obj);
1791: PetscObjectGetClassId(obj, &id);
1792: if (id == PETSCFE_CLASSID) {
1793: PetscFEGetNumComponents((PetscFE)obj, &fNc);
1794: PetscFEGetDimension((PetscFE)obj, &Nb);
1795: } else if (id == PETSCFV_CLASSID) {
1796: PetscFVGetNumComponents((PetscFV)obj, &fNc);
1797: Nb = 1;
1798: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
1799: for (q = 0; q < Nq; ++q) {
1800: const PetscReal wt = quadWeights[q] * fegeom.detJ[q];
1801: PetscFEGeom qgeom;
1803: qgeom.dimEmbed = fegeom.dimEmbed;
1804: qgeom.J = &fegeom.J[q * cdim * cdim];
1805: qgeom.invJ = &fegeom.invJ[q * cdim * cdim];
1806: qgeom.detJ = &fegeom.detJ[q];
1808: if (id == PETSCFE_CLASSID) PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant);
1809: else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
1810: for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt;
1811: vol += wt;
1812: }
1813: foff += Nb;
1814: }
1815: DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1816: for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc];
1817: volsum += vol;
1818: if (debug) {
1819: PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell);
1820: for (fc = 0; fc < Nc; ++fc) {
1821: if (fc) PetscPrintf(PETSC_COMM_SELF, ", ");
1822: PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]));
1823: }
1824: PetscPrintf(PETSC_COMM_SELF, "]\n");
1825: }
1826: }
1827: for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum;
1828: DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1829: DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES);
1830: }
1831: PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1832: return 0;
1833: }
1835: /*@
1836: DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec.
1838: Collective on dm
1840: Input Parameters:
1841: + dm - The `DM`
1842: - locX - The coefficient vector u_h
1844: Output Parameter:
1845: . locC - A `Vec` which holds the Clement interpolant of the gradient
1847: Level: developer
1849: Note:
1850: $\nabla u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| \nabla u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume
1852: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1853: @*/
1854: PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1855: {
1856: DM_Plex *mesh = (DM_Plex *)dm->data;
1857: PetscInt debug = mesh->printFEM;
1858: DM dmC;
1859: PetscQuadrature quad;
1860: PetscScalar *interpolant, *gradsum;
1861: PetscFEGeom fegeom;
1862: PetscReal *coords;
1863: const PetscReal *quadPoints, *quadWeights;
1864: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
1866: PetscCitationsRegister(ClementCitation, &Clementcite);
1867: VecGetDM(locC, &dmC);
1868: VecSet(locC, 0.0);
1869: DMGetDimension(dm, &dim);
1870: DMGetCoordinateDim(dm, &coordDim);
1871: fegeom.dimEmbed = coordDim;
1872: DMGetNumFields(dm, &numFields);
1874: for (field = 0; field < numFields; ++field) {
1875: PetscObject obj;
1876: PetscClassId id;
1877: PetscInt Nc;
1879: DMGetField(dm, field, NULL, &obj);
1880: PetscObjectGetClassId(obj, &id);
1881: if (id == PETSCFE_CLASSID) {
1882: PetscFE fe = (PetscFE)obj;
1884: PetscFEGetQuadrature(fe, &quad);
1885: PetscFEGetNumComponents(fe, &Nc);
1886: } else if (id == PETSCFV_CLASSID) {
1887: PetscFV fv = (PetscFV)obj;
1889: PetscFVGetQuadrature(fv, &quad);
1890: PetscFVGetNumComponents(fv, &Nc);
1891: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1892: numComponents += Nc;
1893: }
1894: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1896: PetscMalloc6(coordDim * numComponents * 2, &gradsum, coordDim * numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ);
1897: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1898: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1899: for (v = vStart; v < vEnd; ++v) {
1900: PetscScalar volsum = 0.0;
1901: PetscInt *star = NULL;
1902: PetscInt starSize, st, d, fc;
1904: PetscArrayzero(gradsum, coordDim * numComponents);
1905: DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1906: for (st = 0; st < starSize * 2; st += 2) {
1907: const PetscInt cell = star[st];
1908: PetscScalar *grad = &gradsum[coordDim * numComponents];
1909: PetscScalar *x = NULL;
1910: PetscReal vol = 0.0;
1912: if ((cell < cStart) || (cell >= cEnd)) continue;
1913: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1914: DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1915: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1916: PetscObject obj;
1917: PetscClassId id;
1918: PetscInt Nb, Nc, q, qc = 0;
1920: PetscArrayzero(grad, coordDim * numComponents);
1921: DMGetField(dm, field, NULL, &obj);
1922: PetscObjectGetClassId(obj, &id);
1923: if (id == PETSCFE_CLASSID) {
1924: PetscFEGetNumComponents((PetscFE)obj, &Nc);
1925: PetscFEGetDimension((PetscFE)obj, &Nb);
1926: } else if (id == PETSCFV_CLASSID) {
1927: PetscFVGetNumComponents((PetscFV)obj, &Nc);
1928: Nb = 1;
1929: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1930: for (q = 0; q < Nq; ++q) {
1931: PetscFEGeom qgeom;
1933: qgeom.dimEmbed = fegeom.dimEmbed;
1934: qgeom.J = &fegeom.J[q * coordDim * coordDim];
1935: qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim];
1936: qgeom.detJ = &fegeom.detJ[q];
1938: if (id == PETSCFE_CLASSID) PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant);
1939: else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1940: for (fc = 0; fc < Nc; ++fc) {
1941: const PetscReal wt = quadWeights[q * qNc + qc];
1943: for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q];
1944: }
1945: vol += quadWeights[q * qNc] * fegeom.detJ[q];
1946: }
1947: fieldOffset += Nb;
1948: qc += Nc;
1949: }
1950: DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1951: for (fc = 0; fc < numComponents; ++fc) {
1952: for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d];
1953: }
1954: volsum += vol;
1955: if (debug) {
1956: PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell);
1957: for (fc = 0; fc < numComponents; ++fc) {
1958: for (d = 0; d < coordDim; ++d) {
1959: if (fc || d > 0) PetscPrintf(PETSC_COMM_SELF, ", ");
1960: PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]));
1961: }
1962: }
1963: PetscPrintf(PETSC_COMM_SELF, "]\n");
1964: }
1965: }
1966: for (fc = 0; fc < numComponents; ++fc) {
1967: for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum;
1968: }
1969: DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1970: DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);
1971: }
1972: PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1973: return 0;
1974: }
1976: static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
1977: {
1978: DM dmAux = NULL;
1979: PetscDS prob, probAux = NULL;
1980: PetscSection section, sectionAux;
1981: Vec locX, locA;
1982: PetscInt dim, numCells = cEnd - cStart, c, f;
1983: PetscBool useFVM = PETSC_FALSE;
1984: /* DS */
1985: PetscInt Nf, totDim, *uOff, *uOff_x, numConstants;
1986: PetscInt NfAux, totDimAux, *aOff;
1987: PetscScalar *u, *a;
1988: const PetscScalar *constants;
1989: /* Geometry */
1990: PetscFEGeom *cgeomFEM;
1991: DM dmGrad;
1992: PetscQuadrature affineQuad = NULL;
1993: Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
1994: PetscFVCellGeom *cgeomFVM;
1995: const PetscScalar *lgrad;
1996: PetscInt maxDegree;
1997: DMField coordField;
1998: IS cellIS;
2000: DMGetDS(dm, &prob);
2001: DMGetDimension(dm, &dim);
2002: DMGetLocalSection(dm, §ion);
2003: DMGetNumFields(dm, &Nf);
2004: /* Determine which discretizations we have */
2005: for (f = 0; f < Nf; ++f) {
2006: PetscObject obj;
2007: PetscClassId id;
2009: PetscDSGetDiscretization(prob, f, &obj);
2010: PetscObjectGetClassId(obj, &id);
2011: if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
2012: }
2013: /* Get local solution with boundary values */
2014: DMGetLocalVector(dm, &locX);
2015: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
2016: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
2017: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
2018: /* Read DS information */
2019: PetscDSGetTotalDimension(prob, &totDim);
2020: PetscDSGetComponentOffsets(prob, &uOff);
2021: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
2022: ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS);
2023: PetscDSGetConstants(prob, &numConstants, &constants);
2024: /* Read Auxiliary DS information */
2025: DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA);
2026: if (locA) {
2027: VecGetDM(locA, &dmAux);
2028: DMGetDS(dmAux, &probAux);
2029: PetscDSGetNumFields(probAux, &NfAux);
2030: DMGetLocalSection(dmAux, §ionAux);
2031: PetscDSGetTotalDimension(probAux, &totDimAux);
2032: PetscDSGetComponentOffsets(probAux, &aOff);
2033: }
2034: /* Allocate data arrays */
2035: PetscCalloc1(numCells * totDim, &u);
2036: if (dmAux) PetscMalloc1(numCells * totDimAux, &a);
2037: /* Read out geometry */
2038: DMGetCoordinateField(dm, &coordField);
2039: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
2040: if (maxDegree <= 1) {
2041: DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad);
2042: if (affineQuad) DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM);
2043: }
2044: if (useFVM) {
2045: PetscFV fv = NULL;
2046: Vec grad;
2047: PetscInt fStart, fEnd;
2048: PetscBool compGrad;
2050: for (f = 0; f < Nf; ++f) {
2051: PetscObject obj;
2052: PetscClassId id;
2054: PetscDSGetDiscretization(prob, f, &obj);
2055: PetscObjectGetClassId(obj, &id);
2056: if (id == PETSCFV_CLASSID) {
2057: fv = (PetscFV)obj;
2058: break;
2059: }
2060: }
2061: PetscFVGetComputeGradients(fv, &compGrad);
2062: PetscFVSetComputeGradients(fv, PETSC_TRUE);
2063: DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);
2064: DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);
2065: PetscFVSetComputeGradients(fv, compGrad);
2066: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM);
2067: /* Reconstruct and limit cell gradients */
2068: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
2069: DMGetGlobalVector(dmGrad, &grad);
2070: DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
2071: /* Communicate gradient values */
2072: DMGetLocalVector(dmGrad, &locGrad);
2073: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
2074: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
2075: DMRestoreGlobalVector(dmGrad, &grad);
2076: /* Handle non-essential (e.g. outflow) boundary values */
2077: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);
2078: VecGetArrayRead(locGrad, &lgrad);
2079: }
2080: /* Read out data from inputs */
2081: for (c = cStart; c < cEnd; ++c) {
2082: PetscScalar *x = NULL;
2083: PetscInt i;
2085: DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);
2086: for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
2087: DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);
2088: if (dmAux) {
2089: DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);
2090: for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
2091: DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);
2092: }
2093: }
2094: /* Do integration for each field */
2095: for (f = 0; f < Nf; ++f) {
2096: PetscObject obj;
2097: PetscClassId id;
2098: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
2100: PetscDSGetDiscretization(prob, f, &obj);
2101: PetscObjectGetClassId(obj, &id);
2102: if (id == PETSCFE_CLASSID) {
2103: PetscFE fe = (PetscFE)obj;
2104: PetscQuadrature q;
2105: PetscFEGeom *chunkGeom = NULL;
2106: PetscInt Nq, Nb;
2108: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
2109: PetscFEGetQuadrature(fe, &q);
2110: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2111: PetscFEGetDimension(fe, &Nb);
2112: blockSize = Nb * Nq;
2113: batchSize = numBlocks * blockSize;
2114: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2115: numChunks = numCells / (numBatches * batchSize);
2116: Ne = numChunks * numBatches * batchSize;
2117: Nr = numCells % (numBatches * batchSize);
2118: offset = numCells - Nr;
2119: if (!affineQuad) DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM);
2120: PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom);
2121: PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral);
2122: PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom);
2123: PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf]);
2124: PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom);
2125: if (!affineQuad) PetscFEGeomDestroy(&cgeomFEM);
2126: } else if (id == PETSCFV_CLASSID) {
2127: PetscInt foff;
2128: PetscPointFunc obj_func;
2129: PetscScalar lint;
2131: PetscDSGetObjective(prob, f, &obj_func);
2132: PetscDSGetFieldOffset(prob, f, &foff);
2133: if (obj_func) {
2134: for (c = 0; c < numCells; ++c) {
2135: PetscScalar *u_x;
2137: DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);
2138: obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, &a[totDimAux * c], NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint);
2139: cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume;
2140: }
2141: }
2142: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
2143: }
2144: /* Cleanup data arrays */
2145: if (useFVM) {
2146: VecRestoreArrayRead(locGrad, &lgrad);
2147: VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM);
2148: DMRestoreLocalVector(dmGrad, &locGrad);
2149: VecDestroy(&faceGeometryFVM);
2150: VecDestroy(&cellGeometryFVM);
2151: DMDestroy(&dmGrad);
2152: }
2153: if (dmAux) PetscFree(a);
2154: PetscFree(u);
2155: /* Cleanup */
2156: if (affineQuad) PetscFEGeomDestroy(&cgeomFEM);
2157: PetscQuadratureDestroy(&affineQuad);
2158: ISDestroy(&cellIS);
2159: DMRestoreLocalVector(dm, &locX);
2160: return 0;
2161: }
2163: /*@
2164: DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
2166: Input Parameters:
2167: + dm - The mesh
2168: . X - Global input vector
2169: - user - The user context
2171: Output Parameter:
2172: . integral - Integral for each field
2174: Level: developer
2176: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2177: @*/
2178: PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
2179: {
2180: DM_Plex *mesh = (DM_Plex *)dm->data;
2181: PetscScalar *cintegral, *lintegral;
2182: PetscInt Nf, f, cellHeight, cStart, cEnd, cell;
2187: PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2188: DMGetNumFields(dm, &Nf);
2189: DMPlexGetVTKCellHeight(dm, &cellHeight);
2190: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2191: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2192: PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral);
2193: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2194: /* Sum up values */
2195: for (cell = cStart; cell < cEnd; ++cell) {
2196: const PetscInt c = cell - cStart;
2198: if (mesh->printFEM > 1) DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]);
2199: for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f];
2200: }
2201: MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm));
2202: if (mesh->printFEM) {
2203: PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:");
2204: for (f = 0; f < Nf; ++f) PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]));
2205: PetscPrintf(PetscObjectComm((PetscObject)dm), "\n");
2206: }
2207: PetscFree2(lintegral, cintegral);
2208: PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2209: return 0;
2210: }
2212: /*@
2213: DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
2215: Input Parameters:
2216: + dm - The mesh
2217: . X - Global input vector
2218: - user - The user context
2220: Output Parameter:
2221: . integral - Cellwise integrals for each field
2223: Level: developer
2225: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2226: @*/
2227: PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
2228: {
2229: DM_Plex *mesh = (DM_Plex *)dm->data;
2230: DM dmF;
2231: PetscSection sectionF;
2232: PetscScalar *cintegral, *af;
2233: PetscInt Nf, f, cellHeight, cStart, cEnd, cell;
2238: PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2239: DMGetNumFields(dm, &Nf);
2240: DMPlexGetVTKCellHeight(dm, &cellHeight);
2241: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2242: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2243: PetscCalloc1((cEnd - cStart) * Nf, &cintegral);
2244: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2245: /* Put values in F*/
2246: VecGetDM(F, &dmF);
2247: DMGetLocalSection(dmF, §ionF);
2248: VecGetArray(F, &af);
2249: for (cell = cStart; cell < cEnd; ++cell) {
2250: const PetscInt c = cell - cStart;
2251: PetscInt dof, off;
2253: if (mesh->printFEM > 1) DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]);
2254: PetscSectionGetDof(sectionF, cell, &dof);
2255: PetscSectionGetOffset(sectionF, cell, &off);
2257: for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f];
2258: }
2259: VecRestoreArray(F, &af);
2260: PetscFree(cintegral);
2261: PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2262: return 0;
2263: }
2265: static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *fintegral, void *user)
2266: {
2267: DM plex = NULL, plexA = NULL;
2268: DMEnclosureType encAux;
2269: PetscDS prob, probAux = NULL;
2270: PetscSection section, sectionAux = NULL;
2271: Vec locA = NULL;
2272: DMField coordField;
2273: PetscInt Nf, totDim, *uOff, *uOff_x;
2274: PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL;
2275: PetscScalar *u, *a = NULL;
2276: const PetscScalar *constants;
2277: PetscInt numConstants, f;
2279: DMGetCoordinateField(dm, &coordField);
2280: DMConvert(dm, DMPLEX, &plex);
2281: DMGetDS(dm, &prob);
2282: DMGetLocalSection(dm, §ion);
2283: PetscSectionGetNumFields(section, &Nf);
2284: /* Determine which discretizations we have */
2285: for (f = 0; f < Nf; ++f) {
2286: PetscObject obj;
2287: PetscClassId id;
2289: PetscDSGetDiscretization(prob, f, &obj);
2290: PetscObjectGetClassId(obj, &id);
2292: }
2293: /* Read DS information */
2294: PetscDSGetTotalDimension(prob, &totDim);
2295: PetscDSGetComponentOffsets(prob, &uOff);
2296: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
2297: PetscDSGetConstants(prob, &numConstants, &constants);
2298: /* Read Auxiliary DS information */
2299: DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA);
2300: if (locA) {
2301: DM dmAux;
2303: VecGetDM(locA, &dmAux);
2304: DMGetEnclosureRelation(dmAux, dm, &encAux);
2305: DMConvert(dmAux, DMPLEX, &plexA);
2306: DMGetDS(dmAux, &probAux);
2307: PetscDSGetNumFields(probAux, &NfAux);
2308: DMGetLocalSection(dmAux, §ionAux);
2309: PetscDSGetTotalDimension(probAux, &totDimAux);
2310: PetscDSGetComponentOffsets(probAux, &aOff);
2311: }
2312: /* Integrate over points */
2313: {
2314: PetscFEGeom *fgeom, *chunkGeom = NULL;
2315: PetscInt maxDegree;
2316: PetscQuadrature qGeom = NULL;
2317: const PetscInt *points;
2318: PetscInt numFaces, face, Nq, field;
2319: PetscInt numChunks, chunkSize, chunk, Nr, offset;
2321: ISGetLocalSize(pointIS, &numFaces);
2322: ISGetIndices(pointIS, &points);
2323: PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a);
2324: DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
2325: for (field = 0; field < Nf; ++field) {
2326: PetscFE fe;
2328: PetscDSGetDiscretization(prob, field, (PetscObject *)&fe);
2329: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);
2330: if (!qGeom) {
2331: PetscFEGetFaceQuadrature(fe, &qGeom);
2332: PetscObjectReference((PetscObject)qGeom);
2333: }
2334: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
2335: DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2336: for (face = 0; face < numFaces; ++face) {
2337: const PetscInt point = points[face], *support;
2338: PetscScalar *x = NULL;
2339: PetscInt i;
2341: DMPlexGetSupport(dm, point, &support);
2342: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
2343: for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
2344: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
2345: if (locA) {
2346: PetscInt subp;
2347: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
2348: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
2349: for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i];
2350: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
2351: }
2352: }
2353: /* Get blocking */
2354: {
2355: PetscQuadrature q;
2356: PetscInt numBatches, batchSize, numBlocks, blockSize;
2357: PetscInt Nq, Nb;
2359: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
2360: PetscFEGetQuadrature(fe, &q);
2361: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2362: PetscFEGetDimension(fe, &Nb);
2363: blockSize = Nb * Nq;
2364: batchSize = numBlocks * blockSize;
2365: chunkSize = numBatches * batchSize;
2366: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2367: numChunks = numFaces / chunkSize;
2368: Nr = numFaces % chunkSize;
2369: offset = numFaces - Nr;
2370: }
2371: /* Do integration for each field */
2372: for (chunk = 0; chunk < numChunks; ++chunk) {
2373: PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom);
2374: PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
2375: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
2376: }
2377: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
2378: PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf]);
2379: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
2380: /* Cleanup data arrays */
2381: DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2382: PetscQuadratureDestroy(&qGeom);
2383: PetscFree2(u, a);
2384: ISRestoreIndices(pointIS, &points);
2385: }
2386: }
2387: if (plex) DMDestroy(&plex);
2388: if (plexA) DMDestroy(&plexA);
2389: return 0;
2390: }
2392: /*@
2393: DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
2395: Input Parameters:
2396: + dm - The mesh
2397: . X - Global input vector
2398: . label - The boundary `DMLabel`
2399: . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values
2400: . vals - The label values to use, or NULL for all values
2401: . func - The function to integrate along the boundary
2402: - user - The user context
2404: Output Parameter:
2405: . integral - Integral for each field
2407: Level: developer
2409: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()`
2410: @*/
2411: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *integral, void *user)
2412: {
2413: Vec locX;
2414: PetscSection section;
2415: DMLabel depthLabel;
2416: IS facetIS;
2417: PetscInt dim, Nf, f, v;
2424: PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2425: DMPlexGetDepthLabel(dm, &depthLabel);
2426: DMGetDimension(dm, &dim);
2427: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
2428: DMGetLocalSection(dm, §ion);
2429: PetscSectionGetNumFields(section, &Nf);
2430: /* Get local solution with boundary values */
2431: DMGetLocalVector(dm, &locX);
2432: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
2433: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
2434: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
2435: /* Loop over label values */
2436: PetscArrayzero(integral, Nf);
2437: for (v = 0; v < numVals; ++v) {
2438: IS pointIS;
2439: PetscInt numFaces, face;
2440: PetscScalar *fintegral;
2442: DMLabelGetStratumIS(label, vals[v], &pointIS);
2443: if (!pointIS) continue; /* No points with that id on this process */
2444: {
2445: IS isectIS;
2447: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
2448: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
2449: ISDestroy(&pointIS);
2450: pointIS = isectIS;
2451: }
2452: ISGetLocalSize(pointIS, &numFaces);
2453: PetscCalloc1(numFaces * Nf, &fintegral);
2454: DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
2455: /* Sum point contributions into integral */
2456: for (f = 0; f < Nf; ++f)
2457: for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f];
2458: PetscFree(fintegral);
2459: ISDestroy(&pointIS);
2460: }
2461: DMRestoreLocalVector(dm, &locX);
2462: ISDestroy(&facetIS);
2463: PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0);
2464: return 0;
2465: }
2467: /*@
2468: DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`.
2470: Input Parameters:
2471: + dmc - The coarse mesh
2472: . dmf - The fine mesh
2473: . isRefined - Flag indicating regular refinement, rather than the same topology
2474: - user - The user context
2476: Output Parameter:
2477: . In - The interpolation matrix
2479: Level: developer
2481: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
2482: @*/
2483: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2484: {
2485: DM_Plex *mesh = (DM_Plex *)dmc->data;
2486: const char *name = "Interpolator";
2487: PetscFE *feRef;
2488: PetscFV *fvRef;
2489: PetscSection fsection, fglobalSection;
2490: PetscSection csection, cglobalSection;
2491: PetscScalar *elemMat;
2492: PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
2493: PetscInt cTotDim = 0, rTotDim = 0;
2495: PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0);
2496: DMGetDimension(dmf, &dim);
2497: DMGetLocalSection(dmf, &fsection);
2498: DMGetGlobalSection(dmf, &fglobalSection);
2499: DMGetLocalSection(dmc, &csection);
2500: DMGetGlobalSection(dmc, &cglobalSection);
2501: PetscSectionGetNumFields(fsection, &Nf);
2502: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
2503: PetscCalloc2(Nf, &feRef, Nf, &fvRef);
2504: for (f = 0; f < Nf; ++f) {
2505: PetscObject obj, objc;
2506: PetscClassId id, idc;
2507: PetscInt rNb = 0, Nc = 0, cNb = 0;
2509: DMGetField(dmf, f, NULL, &obj);
2510: PetscObjectGetClassId(obj, &id);
2511: if (id == PETSCFE_CLASSID) {
2512: PetscFE fe = (PetscFE)obj;
2514: if (isRefined) {
2515: PetscFERefine(fe, &feRef[f]);
2516: } else {
2517: PetscObjectReference((PetscObject)fe);
2518: feRef[f] = fe;
2519: }
2520: PetscFEGetDimension(feRef[f], &rNb);
2521: PetscFEGetNumComponents(fe, &Nc);
2522: } else if (id == PETSCFV_CLASSID) {
2523: PetscFV fv = (PetscFV)obj;
2524: PetscDualSpace Q;
2526: if (isRefined) {
2527: PetscFVRefine(fv, &fvRef[f]);
2528: } else {
2529: PetscObjectReference((PetscObject)fv);
2530: fvRef[f] = fv;
2531: }
2532: PetscFVGetDualSpace(fvRef[f], &Q);
2533: PetscDualSpaceGetDimension(Q, &rNb);
2534: PetscFVGetDualSpace(fv, &Q);
2535: PetscFVGetNumComponents(fv, &Nc);
2536: }
2537: DMGetField(dmc, f, NULL, &objc);
2538: PetscObjectGetClassId(objc, &idc);
2539: if (idc == PETSCFE_CLASSID) {
2540: PetscFE fe = (PetscFE)objc;
2542: PetscFEGetDimension(fe, &cNb);
2543: } else if (id == PETSCFV_CLASSID) {
2544: PetscFV fv = (PetscFV)obj;
2545: PetscDualSpace Q;
2547: PetscFVGetDualSpace(fv, &Q);
2548: PetscDualSpaceGetDimension(Q, &cNb);
2549: }
2550: rTotDim += rNb;
2551: cTotDim += cNb;
2552: }
2553: PetscMalloc1(rTotDim * cTotDim, &elemMat);
2554: PetscArrayzero(elemMat, rTotDim * cTotDim);
2555: for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2556: PetscDualSpace Qref;
2557: PetscQuadrature f;
2558: const PetscReal *qpoints, *qweights;
2559: PetscReal *points;
2560: PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d;
2562: /* Compose points from all dual basis functionals */
2563: if (feRef[fieldI]) {
2564: PetscFEGetDualSpace(feRef[fieldI], &Qref);
2565: PetscFEGetNumComponents(feRef[fieldI], &Nc);
2566: } else {
2567: PetscFVGetDualSpace(fvRef[fieldI], &Qref);
2568: PetscFVGetNumComponents(fvRef[fieldI], &Nc);
2569: }
2570: PetscDualSpaceGetDimension(Qref, &fpdim);
2571: for (i = 0; i < fpdim; ++i) {
2572: PetscDualSpaceGetFunctional(Qref, i, &f);
2573: PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
2574: npoints += Np;
2575: }
2576: PetscMalloc1(npoints * dim, &points);
2577: for (i = 0, k = 0; i < fpdim; ++i) {
2578: PetscDualSpaceGetFunctional(Qref, i, &f);
2579: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2580: for (p = 0; p < Np; ++p, ++k)
2581: for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d];
2582: }
2584: for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
2585: PetscObject obj;
2586: PetscClassId id;
2587: PetscInt NcJ = 0, cpdim = 0, j, qNc;
2589: DMGetField(dmc, fieldJ, NULL, &obj);
2590: PetscObjectGetClassId(obj, &id);
2591: if (id == PETSCFE_CLASSID) {
2592: PetscFE fe = (PetscFE)obj;
2593: PetscTabulation T = NULL;
2595: /* Evaluate basis at points */
2596: PetscFEGetNumComponents(fe, &NcJ);
2597: PetscFEGetDimension(fe, &cpdim);
2598: /* For now, fields only interpolate themselves */
2599: if (fieldI == fieldJ) {
2601: PetscFECreateTabulation(fe, 1, npoints, points, 0, &T);
2602: for (i = 0, k = 0; i < fpdim; ++i) {
2603: PetscDualSpaceGetFunctional(Qref, i, &f);
2604: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2606: for (p = 0; p < Np; ++p, ++k) {
2607: for (j = 0; j < cpdim; ++j) {
2608: /*
2609: cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2610: offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields
2611: fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2612: qNC, Nc, Ncj, c: Number of components in this field
2613: Np, p: Number of quad points in the fine grid functional i
2614: k: i*Np + p, overall point number for the interpolation
2615: */
2616: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += T->T[0][k * cpdim * NcJ + j * Nc + c] * qweights[p * qNc + c];
2617: }
2618: }
2619: }
2620: PetscTabulationDestroy(&T);
2621: }
2622: } else if (id == PETSCFV_CLASSID) {
2623: PetscFV fv = (PetscFV)obj;
2625: /* Evaluate constant function at points */
2626: PetscFVGetNumComponents(fv, &NcJ);
2627: cpdim = 1;
2628: /* For now, fields only interpolate themselves */
2629: if (fieldI == fieldJ) {
2631: for (i = 0, k = 0; i < fpdim; ++i) {
2632: PetscDualSpaceGetFunctional(Qref, i, &f);
2633: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2635: for (p = 0; p < Np; ++p, ++k) {
2636: for (j = 0; j < cpdim; ++j) {
2637: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c];
2638: }
2639: }
2640: }
2641: }
2642: }
2643: offsetJ += cpdim;
2644: }
2645: offsetI += fpdim;
2646: PetscFree(points);
2647: }
2648: if (mesh->printFEM > 1) DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);
2649: /* Preallocate matrix */
2650: {
2651: Mat preallocator;
2652: PetscScalar *vals;
2653: PetscInt *cellCIndices, *cellFIndices;
2654: PetscInt locRows, locCols, cell;
2656: MatGetLocalSize(In, &locRows, &locCols);
2657: MatCreate(PetscObjectComm((PetscObject)In), &preallocator);
2658: MatSetType(preallocator, MATPREALLOCATOR);
2659: MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
2660: MatSetUp(preallocator);
2661: PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices);
2662: for (cell = cStart; cell < cEnd; ++cell) {
2663: if (isRefined) {
2664: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
2665: MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
2666: } else {
2667: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES);
2668: }
2669: }
2670: PetscFree3(vals, cellCIndices, cellFIndices);
2671: MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
2672: MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
2673: MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
2674: MatDestroy(&preallocator);
2675: }
2676: /* Fill matrix */
2677: MatZeroEntries(In);
2678: for (c = cStart; c < cEnd; ++c) {
2679: if (isRefined) {
2680: DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2681: } else {
2682: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2683: }
2684: }
2685: for (f = 0; f < Nf; ++f) PetscFEDestroy(&feRef[f]);
2686: PetscFree2(feRef, fvRef);
2687: PetscFree(elemMat);
2688: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2689: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2690: if (mesh->printFEM > 1) {
2691: PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
2692: MatChop(In, 1.0e-10);
2693: MatView(In, NULL);
2694: }
2695: PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0);
2696: return 0;
2697: }
2699: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2700: {
2701: SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness");
2702: }
2704: /*@
2705: DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`.
2707: Input Parameters:
2708: + dmf - The fine mesh
2709: . dmc - The coarse mesh
2710: - user - The user context
2712: Output Parameter:
2713: . In - The interpolation matrix
2715: Level: developer
2717: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
2718: @*/
2719: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2720: {
2721: DM_Plex *mesh = (DM_Plex *)dmf->data;
2722: const char *name = "Interpolator";
2723: PetscDS prob;
2724: Mat interp;
2725: PetscSection fsection, globalFSection;
2726: PetscSection csection, globalCSection;
2727: PetscInt locRows, locCols;
2728: PetscReal *x, *v0, *J, *invJ, detJ;
2729: PetscReal *v0c, *Jc, *invJc, detJc;
2730: PetscScalar *elemMat;
2731: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s;
2733: PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0);
2734: DMGetCoordinateDim(dmc, &dim);
2735: DMGetDS(dmc, &prob);
2736: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2737: PetscDSGetNumFields(prob, &Nf);
2738: PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ);
2739: PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc);
2740: DMGetLocalSection(dmf, &fsection);
2741: DMGetGlobalSection(dmf, &globalFSection);
2742: DMGetLocalSection(dmc, &csection);
2743: DMGetGlobalSection(dmc, &globalCSection);
2744: DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd);
2745: PetscDSGetTotalDimension(prob, &totDim);
2746: PetscMalloc1(totDim, &elemMat);
2748: MatGetLocalSize(In, &locRows, &locCols);
2749: MatCreate(PetscObjectComm((PetscObject)In), &interp);
2750: MatSetType(interp, MATPREALLOCATOR);
2751: MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
2752: MatSetUp(interp);
2753: for (s = 0; s < 2; ++s) {
2754: for (field = 0; field < Nf; ++field) {
2755: PetscObject obj;
2756: PetscClassId id;
2757: PetscDualSpace Q = NULL;
2758: PetscTabulation T = NULL;
2759: PetscQuadrature f;
2760: const PetscReal *qpoints, *qweights;
2761: PetscInt Nc, qNc, Np, fpdim, off, i, d;
2763: PetscDSGetFieldOffset(prob, field, &off);
2764: PetscDSGetDiscretization(prob, field, &obj);
2765: PetscObjectGetClassId(obj, &id);
2766: if (id == PETSCFE_CLASSID) {
2767: PetscFE fe = (PetscFE)obj;
2769: PetscFEGetDualSpace(fe, &Q);
2770: PetscFEGetNumComponents(fe, &Nc);
2771: if (s) PetscFECreateTabulation(fe, 1, 1, x, 0, &T);
2772: } else if (id == PETSCFV_CLASSID) {
2773: PetscFV fv = (PetscFV)obj;
2775: PetscFVGetDualSpace(fv, &Q);
2776: Nc = 1;
2777: } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
2778: PetscDualSpaceGetDimension(Q, &fpdim);
2779: /* For each fine grid cell */
2780: for (cell = cStart; cell < cEnd; ++cell) {
2781: PetscInt *findices, *cindices;
2782: PetscInt numFIndices, numCIndices;
2784: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2785: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2787: for (i = 0; i < fpdim; ++i) {
2788: Vec pointVec;
2789: PetscScalar *pV;
2790: PetscSF coarseCellSF = NULL;
2791: const PetscSFNode *coarseCells;
2792: PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j;
2794: /* Get points from the dual basis functional quadrature */
2795: PetscDualSpaceGetFunctional(Q, i, &f);
2796: PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2798: VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec);
2799: VecSetBlockSize(pointVec, dim);
2800: VecGetArray(pointVec, &pV);
2801: for (q = 0; q < Np; ++q) {
2802: const PetscReal xi0[3] = {-1., -1., -1.};
2804: /* Transform point to real space */
2805: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
2806: for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
2807: }
2808: VecRestoreArray(pointVec, &pV);
2809: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2810: /* OPT: Read this out from preallocation information */
2811: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2812: /* Update preallocation info */
2813: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2815: VecGetArray(pointVec, &pV);
2816: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2817: PetscReal pVReal[3];
2818: const PetscReal xi0[3] = {-1., -1., -1.};
2820: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2821: if (id == PETSCFE_CLASSID) PetscFEGetDimension((PetscFE)obj, &cpdim);
2822: else cpdim = 1;
2824: if (s) {
2825: /* Transform points from real space to coarse reference space */
2826: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2827: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
2828: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
2830: if (id == PETSCFE_CLASSID) {
2831: /* Evaluate coarse basis on contained point */
2832: PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T);
2833: PetscArrayzero(elemMat, cpdim);
2834: /* Get elemMat entries by multiplying by weight */
2835: for (j = 0; j < cpdim; ++j) {
2836: for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c];
2837: }
2838: } else {
2839: for (j = 0; j < cpdim; ++j) {
2840: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c];
2841: }
2842: }
2843: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);
2844: }
2845: /* Update interpolator */
2847: MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES);
2848: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2849: }
2850: VecRestoreArray(pointVec, &pV);
2851: PetscSFDestroy(&coarseCellSF);
2852: VecDestroy(&pointVec);
2853: }
2854: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2855: }
2856: if (s && id == PETSCFE_CLASSID) PetscTabulationDestroy(&T);
2857: }
2858: if (!s) {
2859: MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY);
2860: MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY);
2861: MatPreallocatorPreallocate(interp, PETSC_TRUE, In);
2862: MatDestroy(&interp);
2863: interp = In;
2864: }
2865: }
2866: PetscFree3(v0, J, invJ);
2867: PetscFree3(v0c, Jc, invJc);
2868: PetscFree(elemMat);
2869: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2870: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2871: PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0);
2872: return 0;
2873: }
2875: /*@
2876: DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`.
2878: Input Parameters:
2879: + dmf - The fine mesh
2880: . dmc - The coarse mesh
2881: - user - The user context
2883: Output Parameter:
2884: . mass - The mass matrix
2886: Level: developer
2888: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
2889: @*/
2890: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2891: {
2892: DM_Plex *mesh = (DM_Plex *)dmf->data;
2893: const char *name = "Mass Matrix";
2894: PetscDS prob;
2895: PetscSection fsection, csection, globalFSection, globalCSection;
2896: PetscHSetIJ ht;
2897: PetscLayout rLayout;
2898: PetscInt *dnz, *onz;
2899: PetscInt locRows, rStart, rEnd;
2900: PetscReal *x, *v0, *J, *invJ, detJ;
2901: PetscReal *v0c, *Jc, *invJc, detJc;
2902: PetscScalar *elemMat;
2903: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2905: DMGetCoordinateDim(dmc, &dim);
2906: DMGetDS(dmc, &prob);
2907: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2908: PetscDSGetNumFields(prob, &Nf);
2909: PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ);
2910: PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc);
2911: DMGetLocalSection(dmf, &fsection);
2912: DMGetGlobalSection(dmf, &globalFSection);
2913: DMGetLocalSection(dmc, &csection);
2914: DMGetGlobalSection(dmc, &globalCSection);
2915: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2916: PetscDSGetTotalDimension(prob, &totDim);
2917: PetscMalloc1(totDim, &elemMat);
2919: MatGetLocalSize(mass, &locRows, NULL);
2920: PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout);
2921: PetscLayoutSetLocalSize(rLayout, locRows);
2922: PetscLayoutSetBlockSize(rLayout, 1);
2923: PetscLayoutSetUp(rLayout);
2924: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2925: PetscLayoutDestroy(&rLayout);
2926: PetscCalloc2(locRows, &dnz, locRows, &onz);
2927: PetscHSetIJCreate(&ht);
2928: for (field = 0; field < Nf; ++field) {
2929: PetscObject obj;
2930: PetscClassId id;
2931: PetscQuadrature quad;
2932: const PetscReal *qpoints;
2933: PetscInt Nq, Nc, i, d;
2935: PetscDSGetDiscretization(prob, field, &obj);
2936: PetscObjectGetClassId(obj, &id);
2937: if (id == PETSCFE_CLASSID) PetscFEGetQuadrature((PetscFE)obj, &quad);
2938: else PetscFVGetQuadrature((PetscFV)obj, &quad);
2939: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2940: /* For each fine grid cell */
2941: for (cell = cStart; cell < cEnd; ++cell) {
2942: Vec pointVec;
2943: PetscScalar *pV;
2944: PetscSF coarseCellSF = NULL;
2945: const PetscSFNode *coarseCells;
2946: PetscInt numCoarseCells, q, c;
2947: PetscInt *findices, *cindices;
2948: PetscInt numFIndices, numCIndices;
2950: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2951: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2952: /* Get points from the quadrature */
2953: VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec);
2954: VecSetBlockSize(pointVec, dim);
2955: VecGetArray(pointVec, &pV);
2956: for (q = 0; q < Nq; ++q) {
2957: const PetscReal xi0[3] = {-1., -1., -1.};
2959: /* Transform point to real space */
2960: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
2961: for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
2962: }
2963: VecRestoreArray(pointVec, &pV);
2964: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2965: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2966: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2967: /* Update preallocation info */
2968: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2970: {
2971: PetscHashIJKey key;
2972: PetscBool missing;
2974: for (i = 0; i < numFIndices; ++i) {
2975: key.i = findices[i];
2976: if (key.i >= 0) {
2977: /* Get indices for coarse elements */
2978: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2979: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2980: for (c = 0; c < numCIndices; ++c) {
2981: key.j = cindices[c];
2982: if (key.j < 0) continue;
2983: PetscHSetIJQueryAdd(ht, key, &missing);
2984: if (missing) {
2985: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart];
2986: else ++onz[key.i - rStart];
2987: }
2988: }
2989: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2990: }
2991: }
2992: }
2993: }
2994: PetscSFDestroy(&coarseCellSF);
2995: VecDestroy(&pointVec);
2996: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2997: }
2998: }
2999: PetscHSetIJDestroy(&ht);
3000: MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
3001: MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
3002: PetscFree2(dnz, onz);
3003: for (field = 0; field < Nf; ++field) {
3004: PetscObject obj;
3005: PetscClassId id;
3006: PetscTabulation T, Tfine;
3007: PetscQuadrature quad;
3008: const PetscReal *qpoints, *qweights;
3009: PetscInt Nq, Nc, i, d;
3011: PetscDSGetDiscretization(prob, field, &obj);
3012: PetscObjectGetClassId(obj, &id);
3013: if (id == PETSCFE_CLASSID) {
3014: PetscFEGetQuadrature((PetscFE)obj, &quad);
3015: PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine);
3016: PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T);
3017: } else {
3018: PetscFVGetQuadrature((PetscFV)obj, &quad);
3019: }
3020: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
3021: /* For each fine grid cell */
3022: for (cell = cStart; cell < cEnd; ++cell) {
3023: Vec pointVec;
3024: PetscScalar *pV;
3025: PetscSF coarseCellSF = NULL;
3026: const PetscSFNode *coarseCells;
3027: PetscInt numCoarseCells, cpdim, q, c, j;
3028: PetscInt *findices, *cindices;
3029: PetscInt numFIndices, numCIndices;
3031: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3032: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
3033: /* Get points from the quadrature */
3034: VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec);
3035: VecSetBlockSize(pointVec, dim);
3036: VecGetArray(pointVec, &pV);
3037: for (q = 0; q < Nq; ++q) {
3038: const PetscReal xi0[3] = {-1., -1., -1.};
3040: /* Transform point to real space */
3041: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3042: for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3043: }
3044: VecRestoreArray(pointVec, &pV);
3045: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
3046: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
3047: /* Update matrix */
3048: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
3050: VecGetArray(pointVec, &pV);
3051: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3052: PetscReal pVReal[3];
3053: const PetscReal xi0[3] = {-1., -1., -1.};
3055: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3056: /* Transform points from real space to coarse reference space */
3057: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
3058: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
3059: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3061: if (id == PETSCFE_CLASSID) {
3062: PetscFE fe = (PetscFE)obj;
3064: /* Evaluate coarse basis on contained point */
3065: PetscFEGetDimension(fe, &cpdim);
3066: PetscFEComputeTabulation(fe, 1, x, 0, T);
3067: /* Get elemMat entries by multiplying by weight */
3068: for (i = 0; i < numFIndices; ++i) {
3069: PetscArrayzero(elemMat, cpdim);
3070: for (j = 0; j < cpdim; ++j) {
3071: for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * Tfine->T[0][(ccell * numFIndices + i) * Nc + c] * qweights[ccell * Nc + c] * detJ;
3072: }
3073: /* Update interpolator */
3074: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);
3076: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3077: }
3078: } else {
3079: cpdim = 1;
3080: for (i = 0; i < numFIndices; ++i) {
3081: PetscArrayzero(elemMat, cpdim);
3082: for (j = 0; j < cpdim; ++j) {
3083: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ;
3084: }
3085: /* Update interpolator */
3086: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);
3087: PetscPrintf(PETSC_COMM_SELF, "Nq: %" PetscInt_FMT " %" PetscInt_FMT " Nf: %" PetscInt_FMT " %" PetscInt_FMT " Nc: %" PetscInt_FMT " %" PetscInt_FMT "\n", ccell, Nq, i, numFIndices, j, numCIndices);
3089: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3090: }
3091: }
3092: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3093: }
3094: VecRestoreArray(pointVec, &pV);
3095: PetscSFDestroy(&coarseCellSF);
3096: VecDestroy(&pointVec);
3097: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3098: }
3099: if (id == PETSCFE_CLASSID) PetscTabulationDestroy(&T);
3100: }
3101: PetscFree3(v0, J, invJ);
3102: PetscFree3(v0c, Jc, invJc);
3103: PetscFree(elemMat);
3104: MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
3105: MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
3106: return 0;
3107: }
3109: /*@
3110: DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
3112: Input Parameters:
3113: + dmc - The coarse mesh
3114: - dmf - The fine mesh
3115: - user - The user context
3117: Output Parameter:
3118: . sc - The mapping
3120: Level: developer
3122: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
3123: @*/
3124: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3125: {
3126: PetscDS prob;
3127: PetscFE *feRef;
3128: PetscFV *fvRef;
3129: Vec fv, cv;
3130: IS fis, cis;
3131: PetscSection fsection, fglobalSection, csection, cglobalSection;
3132: PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3133: PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
3134: PetscBool *needAvg;
3136: PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0);
3137: DMGetDimension(dmf, &dim);
3138: DMGetLocalSection(dmf, &fsection);
3139: DMGetGlobalSection(dmf, &fglobalSection);
3140: DMGetLocalSection(dmc, &csection);
3141: DMGetGlobalSection(dmc, &cglobalSection);
3142: PetscSectionGetNumFields(fsection, &Nf);
3143: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
3144: DMGetDS(dmc, &prob);
3145: PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg);
3146: for (f = 0; f < Nf; ++f) {
3147: PetscObject obj;
3148: PetscClassId id;
3149: PetscInt fNb = 0, Nc = 0;
3151: PetscDSGetDiscretization(prob, f, &obj);
3152: PetscObjectGetClassId(obj, &id);
3153: if (id == PETSCFE_CLASSID) {
3154: PetscFE fe = (PetscFE)obj;
3155: PetscSpace sp;
3156: PetscInt maxDegree;
3158: PetscFERefine(fe, &feRef[f]);
3159: PetscFEGetDimension(feRef[f], &fNb);
3160: PetscFEGetNumComponents(fe, &Nc);
3161: PetscFEGetBasisSpace(fe, &sp);
3162: PetscSpaceGetDegree(sp, NULL, &maxDegree);
3163: if (!maxDegree) needAvg[f] = PETSC_TRUE;
3164: } else if (id == PETSCFV_CLASSID) {
3165: PetscFV fv = (PetscFV)obj;
3166: PetscDualSpace Q;
3168: PetscFVRefine(fv, &fvRef[f]);
3169: PetscFVGetDualSpace(fvRef[f], &Q);
3170: PetscDualSpaceGetDimension(Q, &fNb);
3171: PetscFVGetNumComponents(fv, &Nc);
3172: needAvg[f] = PETSC_TRUE;
3173: }
3174: fTotDim += fNb;
3175: }
3176: PetscDSGetTotalDimension(prob, &cTotDim);
3177: PetscMalloc1(cTotDim, &cmap);
3178: for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
3179: PetscFE feC;
3180: PetscFV fvC;
3181: PetscDualSpace QF, QC;
3182: PetscInt order = -1, NcF, NcC, fpdim, cpdim;
3184: if (feRef[field]) {
3185: PetscDSGetDiscretization(prob, field, (PetscObject *)&feC);
3186: PetscFEGetNumComponents(feC, &NcC);
3187: PetscFEGetNumComponents(feRef[field], &NcF);
3188: PetscFEGetDualSpace(feRef[field], &QF);
3189: PetscDualSpaceGetOrder(QF, &order);
3190: PetscDualSpaceGetDimension(QF, &fpdim);
3191: PetscFEGetDualSpace(feC, &QC);
3192: PetscDualSpaceGetDimension(QC, &cpdim);
3193: } else {
3194: PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC);
3195: PetscFVGetNumComponents(fvC, &NcC);
3196: PetscFVGetNumComponents(fvRef[field], &NcF);
3197: PetscFVGetDualSpace(fvRef[field], &QF);
3198: PetscDualSpaceGetDimension(QF, &fpdim);
3199: PetscFVGetDualSpace(fvC, &QC);
3200: PetscDualSpaceGetDimension(QC, &cpdim);
3201: }
3203: for (c = 0; c < cpdim; ++c) {
3204: PetscQuadrature cfunc;
3205: const PetscReal *cqpoints, *cqweights;
3206: PetscInt NqcC, NpC;
3207: PetscBool found = PETSC_FALSE;
3209: PetscDualSpaceGetFunctional(QC, c, &cfunc);
3210: PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
3213: for (f = 0; f < fpdim; ++f) {
3214: PetscQuadrature ffunc;
3215: const PetscReal *fqpoints, *fqweights;
3216: PetscReal sum = 0.0;
3217: PetscInt NqcF, NpF;
3219: PetscDualSpaceGetFunctional(QF, f, &ffunc);
3220: PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
3222: if (NpC != NpF) continue;
3223: for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
3224: if (sum > 1.0e-9) continue;
3225: for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]);
3226: if (sum < 1.0e-9) continue;
3227: cmap[offsetC + c] = offsetF + f;
3228: found = PETSC_TRUE;
3229: break;
3230: }
3231: if (!found) {
3232: /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3233: if (fvRef[field] || (feRef[field] && order == 0)) {
3234: cmap[offsetC + c] = offsetF + 0;
3235: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3236: }
3237: }
3238: offsetC += cpdim;
3239: offsetF += fpdim;
3240: }
3241: for (f = 0; f < Nf; ++f) {
3242: PetscFEDestroy(&feRef[f]);
3243: PetscFVDestroy(&fvRef[f]);
3244: }
3245: PetscFree3(feRef, fvRef, needAvg);
3247: DMGetGlobalVector(dmf, &fv);
3248: DMGetGlobalVector(dmc, &cv);
3249: VecGetOwnershipRange(cv, &startC, &endC);
3250: PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
3251: PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices);
3252: PetscMalloc1(m, &cindices);
3253: PetscMalloc1(m, &findices);
3254: for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
3255: for (c = cStart; c < cEnd; ++c) {
3256: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
3257: for (d = 0; d < cTotDim; ++d) {
3258: if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3260: cindices[cellCIndices[d] - startC] = cellCIndices[d];
3261: findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]];
3262: }
3263: }
3264: PetscFree(cmap);
3265: PetscFree2(cellCIndices, cellFIndices);
3267: ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
3268: ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
3269: VecScatterCreate(cv, cis, fv, fis, sc);
3270: ISDestroy(&cis);
3271: ISDestroy(&fis);
3272: DMRestoreGlobalVector(dmf, &fv);
3273: DMRestoreGlobalVector(dmc, &cv);
3274: PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0);
3275: return 0;
3276: }
3278: /*@C
3279: DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
3281: Input Parameters:
3282: + dm - The `DM`
3283: . cellIS - The cells to include
3284: . locX - A local vector with the solution fields
3285: . locX_t - A local vector with solution field time derivatives, or NULL
3286: - locA - A local vector with auxiliary fields, or NULL
3288: Output Parameters:
3289: + u - The field coefficients
3290: . u_t - The fields derivative coefficients
3291: - a - The auxiliary field coefficients
3293: Level: developer
3295: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
3296: @*/
3297: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3298: {
3299: DM plex, plexA = NULL;
3300: DMEnclosureType encAux;
3301: PetscSection section, sectionAux;
3302: PetscDS prob;
3303: const PetscInt *cells;
3304: PetscInt cStart, cEnd, numCells, totDim, totDimAux, c;
3313: DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
3314: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3315: DMGetLocalSection(dm, §ion);
3316: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
3317: PetscDSGetTotalDimension(prob, &totDim);
3318: if (locA) {
3319: DM dmAux;
3320: PetscDS probAux;
3322: VecGetDM(locA, &dmAux);
3323: DMGetEnclosureRelation(dmAux, dm, &encAux);
3324: DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3325: DMGetLocalSection(dmAux, §ionAux);
3326: DMGetDS(dmAux, &probAux);
3327: PetscDSGetTotalDimension(probAux, &totDimAux);
3328: }
3329: numCells = cEnd - cStart;
3330: DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u);
3331: if (locX_t) DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t);
3332: else *u_t = NULL;
3333: if (locA) DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a);
3334: else *a = NULL;
3335: for (c = cStart; c < cEnd; ++c) {
3336: const PetscInt cell = cells ? cells[c] : c;
3337: const PetscInt cind = c - cStart;
3338: PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
3339: PetscInt i;
3341: DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
3342: for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i];
3343: DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
3344: if (locX_t) {
3345: DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
3346: for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i];
3347: DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
3348: }
3349: if (locA) {
3350: PetscInt subcell;
3351: DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell);
3352: DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3353: for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i];
3354: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3355: }
3356: }
3357: DMDestroy(&plex);
3358: if (locA) DMDestroy(&plexA);
3359: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3360: return 0;
3361: }
3363: /*@C
3364: DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
3366: Input Parameters:
3367: + dm - The `DM`
3368: . cellIS - The cells to include
3369: . locX - A local vector with the solution fields
3370: . locX_t - A local vector with solution field time derivatives, or NULL
3371: - locA - A local vector with auxiliary fields, or NULL
3373: Output Parameters:
3374: + u - The field coefficients
3375: . u_t - The fields derivative coefficients
3376: - a - The auxiliary field coefficients
3378: Level: developer
3380: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
3381: @*/
3382: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3383: {
3384: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
3385: if (locX_t) DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);
3386: if (locA) DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);
3387: return 0;
3388: }
3390: /*
3391: Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace
3392: */
3393: static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3394: {
3395: DM plexA[2];
3396: DMEnclosureType encAux[2];
3397: PetscSection sectionAux[2];
3398: const PetscInt *cells;
3399: PetscInt cStart, cEnd, numCells, c, s, totDimAux[2];
3402: if (!locA[0] || !locA[1]) return 0;
3406: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3407: numCells = cEnd - cStart;
3408: for (s = 0; s < 2; ++s) {
3412: DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE);
3413: DMGetEnclosureRelation(dmAux[s], dm, &encAux[s]);
3414: DMGetLocalSection(dmAux[s], §ionAux[s]);
3415: PetscDSGetTotalDimension(dsAux[s], &totDimAux[s]);
3416: DMGetWorkArray(dmAux[s], numCells * totDimAux[s], MPIU_SCALAR, &a[s]);
3417: }
3418: for (c = cStart; c < cEnd; ++c) {
3419: const PetscInt cell = cells ? cells[c] : c;
3420: const PetscInt cind = c - cStart;
3421: const PetscInt *cone, *ornt;
3423: DMPlexGetCone(dm, cell, &cone);
3424: DMPlexGetConeOrientation(dm, cell, &ornt);
3425: for (s = 0; s < 2; ++s) {
3426: const PetscInt *support;
3427: PetscScalar *x = NULL, *al = a[s];
3428: const PetscInt tdA = totDimAux[s];
3429: PetscInt ssize, scell;
3430: PetscInt subface, Na, i;
3432: DMPlexGetSupport(dm, cone[s], &support);
3433: DMPlexGetSupportSize(dm, cone[s], &ssize);
3435: if (support[0] == cell) scell = support[1];
3436: else if (support[1] == cell) scell = support[0];
3437: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[s], cell);
3439: DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface);
3440: DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x);
3441: for (i = 0; i < Na; ++i) al[cind * tdA + i] = x[i];
3442: DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x);
3443: }
3444: }
3445: for (s = 0; s < 2; ++s) DMDestroy(&plexA[s]);
3446: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3447: return 0;
3448: }
3450: static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3451: {
3452: if (!locA[0] || !locA[1]) return 0;
3453: DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0]);
3454: DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1]);
3455: return 0;
3456: }
3458: /*@C
3459: DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
3461: Input Parameters:
3462: + dm - The `DM`
3463: . fStart - The first face to include
3464: . fEnd - The first face to exclude
3465: . locX - A local vector with the solution fields
3466: . locX_t - A local vector with solution field time derivatives, or NULL
3467: . faceGeometry - A local vector with face geometry
3468: . cellGeometry - A local vector with cell geometry
3469: - locaGrad - A local vector with field gradients, or NULL
3471: Output Parameters:
3472: + Nface - The number of faces with field values
3473: . uL - The field values at the left side of the face
3474: - uR - The field values at the right side of the face
3476: Level: developer
3478: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
3479: @*/
3480: PetscErrorCode DMPlexGetFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR)
3481: {
3482: DM dmFace, dmCell, dmGrad = NULL;
3483: PetscSection section;
3484: PetscDS prob;
3485: DMLabel ghostLabel;
3486: const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
3487: PetscBool *isFE;
3488: PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
3498: DMGetDimension(dm, &dim);
3499: DMGetDS(dm, &prob);
3500: DMGetLocalSection(dm, §ion);
3501: PetscDSGetNumFields(prob, &Nf);
3502: PetscDSGetTotalComponents(prob, &Nc);
3503: PetscMalloc1(Nf, &isFE);
3504: for (f = 0; f < Nf; ++f) {
3505: PetscObject obj;
3506: PetscClassId id;
3508: PetscDSGetDiscretization(prob, f, &obj);
3509: PetscObjectGetClassId(obj, &id);
3510: if (id == PETSCFE_CLASSID) {
3511: isFE[f] = PETSC_TRUE;
3512: } else if (id == PETSCFV_CLASSID) {
3513: isFE[f] = PETSC_FALSE;
3514: } else {
3515: isFE[f] = PETSC_FALSE;
3516: }
3517: }
3518: DMGetLabel(dm, "ghost", &ghostLabel);
3519: VecGetArrayRead(locX, &x);
3520: VecGetDM(faceGeometry, &dmFace);
3521: VecGetArrayRead(faceGeometry, &facegeom);
3522: VecGetDM(cellGeometry, &dmCell);
3523: VecGetArrayRead(cellGeometry, &cellgeom);
3524: if (locGrad) {
3525: VecGetDM(locGrad, &dmGrad);
3526: VecGetArrayRead(locGrad, &lgrad);
3527: }
3528: DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL);
3529: DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR);
3530: /* Right now just eat the extra work for FE (could make a cell loop) */
3531: for (face = fStart, iface = 0; face < fEnd; ++face) {
3532: const PetscInt *cells;
3533: PetscFVFaceGeom *fg;
3534: PetscFVCellGeom *cgL, *cgR;
3535: PetscScalar *xL, *xR, *gL, *gR;
3536: PetscScalar *uLl = *uL, *uRl = *uR;
3537: PetscInt ghost, nsupp, nchild;
3539: DMLabelGetValue(ghostLabel, face, &ghost);
3540: DMPlexGetSupportSize(dm, face, &nsupp);
3541: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3542: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3543: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3544: DMPlexGetSupport(dm, face, &cells);
3545: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3546: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3547: for (f = 0; f < Nf; ++f) {
3548: PetscInt off;
3550: PetscDSGetComponentOffset(prob, f, &off);
3551: if (isFE[f]) {
3552: const PetscInt *cone;
3553: PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
3555: xL = xR = NULL;
3556: PetscSectionGetFieldComponents(section, f, &comp);
3557: DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL);
3558: DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR);
3559: DMPlexGetCone(dm, cells[0], &cone);
3560: DMPlexGetConeSize(dm, cells[0], &coneSizeL);
3561: for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL)
3562: if (cone[faceLocL] == face) break;
3563: DMPlexGetCone(dm, cells[1], &cone);
3564: DMPlexGetConeSize(dm, cells[1], &coneSizeR);
3565: for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR)
3566: if (cone[faceLocR] == face) break;
3568: /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
3569: /* TODO: this is a hack that might not be right for nonconforming */
3570: if (faceLocL < coneSizeL) {
3571: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off]);
3572: if (rdof == ldof && faceLocR < coneSizeR) PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]);
3573: else {
3574: for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d];
3575: }
3576: } else {
3577: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]);
3578: PetscSectionGetFieldComponents(section, f, &comp);
3579: for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d];
3580: }
3581: DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL);
3582: DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR);
3583: } else {
3584: PetscFV fv;
3585: PetscInt numComp, c;
3587: PetscDSGetDiscretization(prob, f, (PetscObject *)&fv);
3588: PetscFVGetNumComponents(fv, &numComp);
3589: DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3590: DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3591: if (dmGrad) {
3592: PetscReal dxL[3], dxR[3];
3594: DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
3595: DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
3596: DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
3597: DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
3598: for (c = 0; c < numComp; ++c) {
3599: uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL);
3600: uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR);
3601: }
3602: } else {
3603: for (c = 0; c < numComp; ++c) {
3604: uLl[iface * Nc + off + c] = xL[c];
3605: uRl[iface * Nc + off + c] = xR[c];
3606: }
3607: }
3608: }
3609: }
3610: ++iface;
3611: }
3612: *Nface = iface;
3613: VecRestoreArrayRead(locX, &x);
3614: VecRestoreArrayRead(faceGeometry, &facegeom);
3615: VecRestoreArrayRead(cellGeometry, &cellgeom);
3616: if (locGrad) VecRestoreArrayRead(locGrad, &lgrad);
3617: PetscFree(isFE);
3618: return 0;
3619: }
3621: /*@C
3622: DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
3624: Input Parameters:
3625: + dm - The `DM`
3626: . fStart - The first face to include
3627: . fEnd - The first face to exclude
3628: . locX - A local vector with the solution fields
3629: . locX_t - A local vector with solution field time derivatives, or NULL
3630: . faceGeometry - A local vector with face geometry
3631: . cellGeometry - A local vector with cell geometry
3632: - locaGrad - A local vector with field gradients, or NULL
3634: Output Parameters:
3635: + Nface - The number of faces with field values
3636: . uL - The field values at the left side of the face
3637: - uR - The field values at the right side of the face
3639: Level: developer
3641: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
3642: @*/
3643: PetscErrorCode DMPlexRestoreFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR)
3644: {
3645: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3646: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3647: return 0;
3648: }
3650: /*@C
3651: DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
3653: Input Parameters:
3654: + dm - The `DM`
3655: . fStart - The first face to include
3656: . fEnd - The first face to exclude
3657: . faceGeometry - A local vector with face geometry
3658: - cellGeometry - A local vector with cell geometry
3660: Output Parameters:
3661: + Nface - The number of faces with field values
3662: . fgeom - The extract the face centroid and normal
3663: - vol - The cell volume
3665: Level: developer
3667: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
3668: @*/
3669: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3670: {
3671: DM dmFace, dmCell;
3672: DMLabel ghostLabel;
3673: const PetscScalar *facegeom, *cellgeom;
3674: PetscInt dim, numFaces = fEnd - fStart, iface, face;
3681: DMGetDimension(dm, &dim);
3682: DMGetLabel(dm, "ghost", &ghostLabel);
3683: VecGetDM(faceGeometry, &dmFace);
3684: VecGetArrayRead(faceGeometry, &facegeom);
3685: VecGetDM(cellGeometry, &dmCell);
3686: VecGetArrayRead(cellGeometry, &cellgeom);
3687: PetscMalloc1(numFaces, fgeom);
3688: DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol);
3689: for (face = fStart, iface = 0; face < fEnd; ++face) {
3690: const PetscInt *cells;
3691: PetscFVFaceGeom *fg;
3692: PetscFVCellGeom *cgL, *cgR;
3693: PetscFVFaceGeom *fgeoml = *fgeom;
3694: PetscReal *voll = *vol;
3695: PetscInt ghost, d, nchild, nsupp;
3697: DMLabelGetValue(ghostLabel, face, &ghost);
3698: DMPlexGetSupportSize(dm, face, &nsupp);
3699: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3700: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3701: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3702: DMPlexGetSupport(dm, face, &cells);
3703: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3704: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3705: for (d = 0; d < dim; ++d) {
3706: fgeoml[iface].centroid[d] = fg->centroid[d];
3707: fgeoml[iface].normal[d] = fg->normal[d];
3708: }
3709: voll[iface * 2 + 0] = cgL->volume;
3710: voll[iface * 2 + 1] = cgR->volume;
3711: ++iface;
3712: }
3713: *Nface = iface;
3714: VecRestoreArrayRead(faceGeometry, &facegeom);
3715: VecRestoreArrayRead(cellGeometry, &cellgeom);
3716: return 0;
3717: }
3719: /*@C
3720: DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
3722: Input Parameters:
3723: + dm - The `DM`
3724: . fStart - The first face to include
3725: . fEnd - The first face to exclude
3726: . faceGeometry - A local vector with face geometry
3727: - cellGeometry - A local vector with cell geometry
3729: Output Parameters:
3730: + Nface - The number of faces with field values
3731: . fgeom - The extract the face centroid and normal
3732: - vol - The cell volume
3734: Level: developer
3736: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
3737: @*/
3738: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3739: {
3740: PetscFree(*fgeom);
3741: DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3742: return 0;
3743: }
3745: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3746: {
3747: char composeStr[33] = {0};
3748: PetscObjectId id;
3749: PetscContainer container;
3751: PetscObjectGetId((PetscObject)quad, &id);
3752: PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id);
3753: PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container);
3754: if (container) {
3755: PetscContainerGetPointer(container, (void **)geom);
3756: } else {
3757: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3758: PetscContainerCreate(PETSC_COMM_SELF, &container);
3759: PetscContainerSetPointer(container, (void *)*geom);
3760: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3761: PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container);
3762: PetscContainerDestroy(&container);
3763: }
3764: return 0;
3765: }
3767: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3768: {
3769: *geom = NULL;
3770: return 0;
3771: }
3773: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3774: {
3775: DM_Plex *mesh = (DM_Plex *)dm->data;
3776: const char *name = "Residual";
3777: DM dmAux = NULL;
3778: DMLabel ghostLabel = NULL;
3779: PetscDS prob = NULL;
3780: PetscDS probAux = NULL;
3781: PetscBool useFEM = PETSC_FALSE;
3782: PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3783: DMField coordField = NULL;
3784: Vec locA;
3785: PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3786: IS chunkIS;
3787: const PetscInt *cells;
3788: PetscInt cStart, cEnd, numCells;
3789: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3790: PetscInt maxDegree = PETSC_MAX_INT;
3791: PetscFormKey key;
3792: PetscQuadrature affineQuad = NULL, *quads = NULL;
3793: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
3795: PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0);
3796: /* FEM+FVM */
3797: /* 1: Get sizes from dm and dmAux */
3798: DMGetLabel(dm, "ghost", &ghostLabel);
3799: DMGetDS(dm, &prob);
3800: PetscDSGetNumFields(prob, &Nf);
3801: PetscDSGetTotalDimension(prob, &totDim);
3802: DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA);
3803: if (locA) {
3804: VecGetDM(locA, &dmAux);
3805: DMGetDS(dmAux, &probAux);
3806: PetscDSGetTotalDimension(probAux, &totDimAux);
3807: }
3808: /* 2: Get geometric data */
3809: for (f = 0; f < Nf; ++f) {
3810: PetscObject obj;
3811: PetscClassId id;
3812: PetscBool fimp;
3814: PetscDSGetImplicit(prob, f, &fimp);
3815: if (isImplicit != fimp) continue;
3816: PetscDSGetDiscretization(prob, f, &obj);
3817: PetscObjectGetClassId(obj, &id);
3818: if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
3820: }
3821: if (useFEM) {
3822: DMGetCoordinateField(dm, &coordField);
3823: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
3824: if (maxDegree <= 1) {
3825: DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad);
3826: if (affineQuad) DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
3827: } else {
3828: PetscCalloc2(Nf, &quads, Nf, &geoms);
3829: for (f = 0; f < Nf; ++f) {
3830: PetscObject obj;
3831: PetscClassId id;
3832: PetscBool fimp;
3834: PetscDSGetImplicit(prob, f, &fimp);
3835: if (isImplicit != fimp) continue;
3836: PetscDSGetDiscretization(prob, f, &obj);
3837: PetscObjectGetClassId(obj, &id);
3838: if (id == PETSCFE_CLASSID) {
3839: PetscFE fe = (PetscFE)obj;
3841: PetscFEGetQuadrature(fe, &quads[f]);
3842: PetscObjectReference((PetscObject)quads[f]);
3843: DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
3844: }
3845: }
3846: }
3847: }
3848: /* Loop over chunks */
3849: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3850: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3851: if (useFEM) ISCreate(PETSC_COMM_SELF, &chunkIS);
3852: numCells = cEnd - cStart;
3853: numChunks = 1;
3854: cellChunkSize = numCells / numChunks;
3855: numChunks = PetscMin(1, numCells);
3856: key.label = NULL;
3857: key.value = 0;
3858: key.part = 0;
3859: for (chunk = 0; chunk < numChunks; ++chunk) {
3860: PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL;
3861: PetscReal *vol = NULL;
3862: PetscFVFaceGeom *fgeom = NULL;
3863: PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
3864: PetscInt numFaces = 0;
3866: /* Extract field coefficients */
3867: if (useFEM) {
3868: ISGetPointSubrange(chunkIS, cS, cE, cells);
3869: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3870: DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec);
3871: PetscArrayzero(elemVec, numCells * totDim);
3872: }
3873: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3874: /* Loop over fields */
3875: for (f = 0; f < Nf; ++f) {
3876: PetscObject obj;
3877: PetscClassId id;
3878: PetscBool fimp;
3879: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
3881: key.field = f;
3882: PetscDSGetImplicit(prob, f, &fimp);
3883: if (isImplicit != fimp) continue;
3884: PetscDSGetDiscretization(prob, f, &obj);
3885: PetscObjectGetClassId(obj, &id);
3886: if (id == PETSCFE_CLASSID) {
3887: PetscFE fe = (PetscFE)obj;
3888: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
3889: PetscFEGeom *chunkGeom = NULL;
3890: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3891: PetscInt Nq, Nb;
3893: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3894: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3895: PetscFEGetDimension(fe, &Nb);
3896: blockSize = Nb;
3897: batchSize = numBlocks * blockSize;
3898: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3899: numChunks = numCells / (numBatches * batchSize);
3900: Ne = numChunks * numBatches * batchSize;
3901: Nr = numCells % (numBatches * batchSize);
3902: offset = numCells - Nr;
3903: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3904: /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */
3905: PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom);
3906: PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3907: PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom);
3908: PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim]);
3909: PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom);
3910: } else if (id == PETSCFV_CLASSID) {
3911: PetscFV fv = (PetscFV)obj;
3913: Ne = numFaces;
3914: /* Riemann solve over faces (need fields at face centroids) */
3915: /* We need to evaluate FE fields at those coordinates */
3916: PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3917: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
3918: }
3919: /* Loop over domain */
3920: if (useFEM) {
3921: /* Add elemVec to locX */
3922: for (c = cS; c < cE; ++c) {
3923: const PetscInt cell = cells ? cells[c] : c;
3924: const PetscInt cind = c - cStart;
3926: if (mesh->printFEM > 1) DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]);
3927: if (ghostLabel) {
3928: PetscInt ghostVal;
3930: DMLabelGetValue(ghostLabel, cell, &ghostVal);
3931: if (ghostVal > 0) continue;
3932: }
3933: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES);
3934: }
3935: }
3936: /* Handle time derivative */
3937: if (locX_t) {
3938: PetscScalar *x_t, *fa;
3940: VecGetArray(locF, &fa);
3941: VecGetArray(locX_t, &x_t);
3942: for (f = 0; f < Nf; ++f) {
3943: PetscFV fv;
3944: PetscObject obj;
3945: PetscClassId id;
3946: PetscInt pdim, d;
3948: PetscDSGetDiscretization(prob, f, &obj);
3949: PetscObjectGetClassId(obj, &id);
3950: if (id != PETSCFV_CLASSID) continue;
3951: fv = (PetscFV)obj;
3952: PetscFVGetNumComponents(fv, &pdim);
3953: for (c = cS; c < cE; ++c) {
3954: const PetscInt cell = cells ? cells[c] : c;
3955: PetscScalar *u_t, *r;
3957: if (ghostLabel) {
3958: PetscInt ghostVal;
3960: DMLabelGetValue(ghostLabel, cell, &ghostVal);
3961: if (ghostVal > 0) continue;
3962: }
3963: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3964: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3965: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3966: }
3967: }
3968: VecRestoreArray(locX_t, &x_t);
3969: VecRestoreArray(locF, &fa);
3970: }
3971: if (useFEM) {
3972: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3973: DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec);
3974: }
3975: }
3976: if (useFEM) ISDestroy(&chunkIS);
3977: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3978: /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3979: if (useFEM) {
3980: if (maxDegree <= 1) {
3981: DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
3982: PetscQuadratureDestroy(&affineQuad);
3983: } else {
3984: for (f = 0; f < Nf; ++f) {
3985: DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
3986: PetscQuadratureDestroy(&quads[f]);
3987: }
3988: PetscFree2(quads, geoms);
3989: }
3990: }
3991: PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0);
3992: return 0;
3993: }
3995: /*
3996: We always assemble JacP, and if the matrix is different from Jac and two different sets of point functions are provided, we also assemble Jac
3998: X - The local solution vector
3999: X_t - The local solution time derivative vector, or NULL
4000: */
4001: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
4002: {
4003: DM_Plex *mesh = (DM_Plex *)dm->data;
4004: const char *name = "Jacobian", *nameP = "JacobianPre";
4005: DM dmAux = NULL;
4006: PetscDS prob, probAux = NULL;
4007: PetscSection sectionAux = NULL;
4008: Vec A;
4009: DMField coordField;
4010: PetscFEGeom *cgeomFEM;
4011: PetscQuadrature qGeom = NULL;
4012: Mat J = Jac, JP = JacP;
4013: PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4014: PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE;
4015: const PetscInt *cells;
4016: PetscFormKey key;
4017: PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4019: ISGetLocalSize(cellIS, &numCells);
4020: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4021: PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0);
4022: DMGetDS(dm, &prob);
4023: DMGetAuxiliaryVec(dm, NULL, 0, 0, &A);
4024: if (A) {
4025: VecGetDM(A, &dmAux);
4026: DMGetLocalSection(dmAux, §ionAux);
4027: DMGetDS(dmAux, &probAux);
4028: }
4029: /* Get flags */
4030: PetscDSGetNumFields(prob, &Nf);
4031: DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4032: for (fieldI = 0; fieldI < Nf; ++fieldI) {
4033: PetscObject disc;
4034: PetscClassId id;
4035: PetscDSGetDiscretization(prob, fieldI, &disc);
4036: PetscObjectGetClassId(disc, &id);
4037: if (id == PETSCFE_CLASSID) {
4038: isFE[fieldI] = PETSC_TRUE;
4039: } else if (id == PETSCFV_CLASSID) {
4040: hasFV = PETSC_TRUE;
4041: isFE[fieldI] = PETSC_FALSE;
4042: }
4043: }
4044: PetscDSHasJacobian(prob, &hasJac);
4045: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
4046: PetscDSHasDynamicJacobian(prob, &hasDyn);
4047: assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4048: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
4049: if (hasFV) MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE); /* No allocated space for FV stuff, so ignore the zero entries */
4050: PetscDSGetTotalDimension(prob, &totDim);
4051: if (probAux) PetscDSGetTotalDimension(probAux, &totDimAux);
4052: /* Compute batch sizes */
4053: if (isFE[0]) {
4054: PetscFE fe;
4055: PetscQuadrature q;
4056: PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4058: PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe);
4059: PetscFEGetQuadrature(fe, &q);
4060: PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
4061: PetscFEGetDimension(fe, &Nb);
4062: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4063: blockSize = Nb * numQuadPoints;
4064: batchSize = numBlocks * blockSize;
4065: chunkSize = numBatches * batchSize;
4066: numChunks = numCells / chunkSize + numCells % chunkSize;
4067: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4068: } else {
4069: chunkSize = numCells;
4070: numChunks = 1;
4071: }
4072: /* Get work space */
4073: wsz = (((X ? 1 : 0) + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize;
4074: DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
4075: PetscArrayzero(work, wsz);
4076: off = 0;
4077: u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4078: u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4079: a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL;
4080: elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4081: elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4082: elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4084: /* Setup geometry */
4085: DMGetCoordinateField(dm, &coordField);
4086: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4087: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);
4088: if (!qGeom) {
4089: PetscFE fe;
4091: PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe);
4092: PetscFEGetQuadrature(fe, &qGeom);
4093: PetscObjectReference((PetscObject)qGeom);
4094: }
4095: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4096: /* Compute volume integrals */
4097: if (assembleJac) MatZeroEntries(J);
4098: MatZeroEntries(JP);
4099: key.label = NULL;
4100: key.value = 0;
4101: key.part = 0;
4102: for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4103: const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4104: PetscInt c;
4106: /* Extract values */
4107: for (c = 0; c < Ncell; ++c) {
4108: const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4109: PetscScalar *x = NULL, *x_t = NULL;
4110: PetscInt i;
4112: if (X) {
4113: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
4114: for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
4115: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
4116: }
4117: if (X_t) {
4118: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
4119: for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i];
4120: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
4121: }
4122: if (dmAux) {
4123: DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
4124: for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
4125: DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
4126: }
4127: }
4128: for (fieldI = 0; fieldI < Nf; ++fieldI) {
4129: PetscFE fe;
4130: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe);
4131: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
4132: key.field = fieldI * Nf + fieldJ;
4133: if (hasJac) PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);
4134: if (hasPrec) PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);
4135: if (hasDyn) PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);
4136: }
4137: /* For finite volume, add the identity */
4138: if (!isFE[fieldI]) {
4139: PetscFV fv;
4140: PetscInt eOffset = 0, Nc, fc, foff;
4142: PetscDSGetFieldOffset(prob, fieldI, &foff);
4143: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv);
4144: PetscFVGetNumComponents(fv, &Nc);
4145: for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) {
4146: for (fc = 0; fc < Nc; ++fc) {
4147: const PetscInt i = foff + fc;
4148: if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
4149: if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0;
4150: }
4151: }
4152: }
4153: }
4154: /* Add contribution from X_t */
4155: if (hasDyn) {
4156: for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
4157: }
4158: /* Insert values into matrix */
4159: for (c = 0; c < Ncell; ++c) {
4160: const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4161: if (mesh->printFEM > 1) {
4162: if (hasJac) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim]);
4163: if (hasPrec) DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim]);
4164: }
4165: if (assembleJac) DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES);
4166: DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES);
4167: }
4168: }
4169: /* Cleanup */
4170: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4171: PetscQuadratureDestroy(&qGeom);
4172: if (hasFV) MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);
4173: DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4174: DMRestoreWorkArray(dm, ((1 + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize, MPIU_SCALAR, &work);
4175: /* Compute boundary integrals */
4176: /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
4177: /* Assemble matrix */
4178: if (assembleJac) {
4179: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
4180: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
4181: }
4182: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
4183: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
4184: PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0);
4185: return 0;
4186: }
4188: /******** FEM Assembly Function ********/
4190: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4191: {
4192: PetscBool isPlex;
4194: PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex);
4195: if (isPlex) {
4196: *plex = dm;
4197: PetscObjectReference((PetscObject)dm);
4198: } else {
4199: PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex);
4200: if (!*plex) {
4201: DMConvert(dm, DMPLEX, plex);
4202: PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex);
4203: if (copy) DMCopyAuxiliaryVec(dm, *plex);
4204: } else {
4205: PetscObjectReference((PetscObject)*plex);
4206: }
4207: }
4208: return 0;
4209: }
4211: /*@
4212: DMPlexGetGeometryFVM - Return precomputed geometric data
4214: Collective on dm
4216: Input Parameter:
4217: . dm - The `DM`
4219: Output Parameters:
4220: + facegeom - The values precomputed from face geometry
4221: . cellgeom - The values precomputed from cell geometry
4222: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell
4224: Level: developer
4226: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()`
4227: @*/
4228: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4229: {
4230: DM plex;
4233: DMConvertPlex_Internal(dm, &plex, PETSC_TRUE);
4234: DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4235: if (minRadius) DMPlexGetMinRadius(plex, minRadius);
4236: DMDestroy(&plex);
4237: return 0;
4238: }
4240: /*@
4241: DMPlexGetGradientDM - Return gradient data layout
4243: Collective on dm
4245: Input Parameters:
4246: + dm - The `DM`
4247: - fv - The PetscFV
4249: Output Parameter:
4250: . dmGrad - The layout for gradient values
4252: Level: developer
4254: .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()`
4255: @*/
4256: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4257: {
4258: DM plex;
4259: PetscBool computeGradients;
4264: PetscFVGetComputeGradients(fv, &computeGradients);
4265: if (!computeGradients) {
4266: *dmGrad = NULL;
4267: return 0;
4268: }
4269: DMConvertPlex_Internal(dm, &plex, PETSC_TRUE);
4270: DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4271: DMDestroy(&plex);
4272: return 0;
4273: }
4275: static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4276: {
4277: DM_Plex *mesh = (DM_Plex *)dm->data;
4278: DM plex = NULL, plexA = NULL;
4279: DMEnclosureType encAux;
4280: PetscDS prob, probAux = NULL;
4281: PetscSection section, sectionAux = NULL;
4282: Vec locA = NULL;
4283: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4284: PetscInt totDim, totDimAux = 0;
4286: DMConvert(dm, DMPLEX, &plex);
4287: DMGetLocalSection(dm, §ion);
4288: DMGetDS(dm, &prob);
4289: PetscDSGetTotalDimension(prob, &totDim);
4290: DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA);
4291: if (locA) {
4292: DM dmAux;
4294: VecGetDM(locA, &dmAux);
4295: DMGetEnclosureRelation(dmAux, dm, &encAux);
4296: DMConvert(dmAux, DMPLEX, &plexA);
4297: DMGetDS(plexA, &probAux);
4298: PetscDSGetTotalDimension(probAux, &totDimAux);
4299: DMGetLocalSection(plexA, §ionAux);
4300: }
4301: {
4302: PetscFEGeom *fgeom;
4303: PetscInt maxDegree;
4304: PetscQuadrature qGeom = NULL;
4305: IS pointIS;
4306: const PetscInt *points;
4307: PetscInt numFaces, face, Nq;
4309: DMLabelGetStratumIS(key.label, key.value, &pointIS);
4310: if (!pointIS) goto end; /* No points with that id on this process */
4311: {
4312: IS isectIS;
4314: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
4315: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
4316: ISDestroy(&pointIS);
4317: pointIS = isectIS;
4318: }
4319: ISGetLocalSize(pointIS, &numFaces);
4320: ISGetIndices(pointIS, &points);
4321: PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a);
4322: DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
4323: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);
4324: if (!qGeom) {
4325: PetscFE fe;
4327: PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe);
4328: PetscFEGetFaceQuadrature(fe, &qGeom);
4329: PetscObjectReference((PetscObject)qGeom);
4330: }
4331: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
4332: DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
4333: for (face = 0; face < numFaces; ++face) {
4334: const PetscInt point = points[face], *support;
4335: PetscScalar *x = NULL;
4336: PetscInt i;
4338: DMPlexGetSupport(dm, point, &support);
4339: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
4340: for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
4341: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
4342: if (locX_t) {
4343: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
4344: for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
4345: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
4346: }
4347: if (locA) {
4348: PetscInt subp;
4350: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
4351: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
4352: for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
4353: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
4354: }
4355: }
4356: PetscArrayzero(elemVec, numFaces * totDim);
4357: {
4358: PetscFE fe;
4359: PetscInt Nb;
4360: PetscFEGeom *chunkGeom = NULL;
4361: /* Conforming batches */
4362: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
4363: /* Remainder */
4364: PetscInt Nr, offset;
4366: PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe);
4367: PetscFEGetDimension(fe, &Nb);
4368: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4369: /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
4370: blockSize = Nb;
4371: batchSize = numBlocks * blockSize;
4372: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4373: numChunks = numFaces / (numBatches * batchSize);
4374: Ne = numChunks * numBatches * batchSize;
4375: Nr = numFaces % (numBatches * batchSize);
4376: offset = numFaces - Nr;
4377: PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom);
4378: PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4379: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
4380: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
4381: PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim]);
4382: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
4383: }
4384: for (face = 0; face < numFaces; ++face) {
4385: const PetscInt point = points[face], *support;
4387: if (mesh->printFEM > 1) DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim]);
4388: DMPlexGetSupport(plex, point, &support);
4389: DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES);
4390: }
4391: DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
4392: PetscQuadratureDestroy(&qGeom);
4393: ISRestoreIndices(pointIS, &points);
4394: ISDestroy(&pointIS);
4395: PetscFree4(u, u_t, elemVec, a);
4396: }
4397: end:
4398: DMDestroy(&plex);
4399: DMDestroy(&plexA);
4400: return 0;
4401: }
4403: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF)
4404: {
4405: DMField coordField;
4406: DMLabel depthLabel;
4407: IS facetIS;
4408: PetscInt dim;
4410: DMGetDimension(dm, &dim);
4411: DMPlexGetDepthLabel(dm, &depthLabel);
4412: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4413: DMGetCoordinateField(dm, &coordField);
4414: DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS);
4415: ISDestroy(&facetIS);
4416: return 0;
4417: }
4419: PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4420: {
4421: PetscDS prob;
4422: PetscInt numBd, bd;
4423: DMField coordField = NULL;
4424: IS facetIS = NULL;
4425: DMLabel depthLabel;
4426: PetscInt dim;
4428: DMGetDS(dm, &prob);
4429: DMPlexGetDepthLabel(dm, &depthLabel);
4430: DMGetDimension(dm, &dim);
4431: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4432: PetscDSGetNumBoundary(prob, &numBd);
4433: for (bd = 0; bd < numBd; ++bd) {
4434: PetscWeakForm wf;
4435: DMBoundaryConditionType type;
4436: DMLabel label;
4437: const PetscInt *values;
4438: PetscInt field, numValues, v;
4439: PetscObject obj;
4440: PetscClassId id;
4441: PetscFormKey key;
4443: PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL);
4444: if (type & DM_BC_ESSENTIAL) continue;
4445: PetscDSGetDiscretization(prob, field, &obj);
4446: PetscObjectGetClassId(obj, &id);
4447: if (id != PETSCFE_CLASSID) continue;
4448: if (!facetIS) {
4449: DMLabel depthLabel;
4450: PetscInt dim;
4452: DMPlexGetDepthLabel(dm, &depthLabel);
4453: DMGetDimension(dm, &dim);
4454: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4455: }
4456: DMGetCoordinateField(dm, &coordField);
4457: for (v = 0; v < numValues; ++v) {
4458: key.label = label;
4459: key.value = values[v];
4460: key.field = field;
4461: key.part = 0;
4462: DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS);
4463: }
4464: }
4465: ISDestroy(&facetIS);
4466: return 0;
4467: }
4469: PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4470: {
4471: DM_Plex *mesh = (DM_Plex *)dm->data;
4472: const char *name = "Residual";
4473: DM dmAux = NULL;
4474: DM dmGrad = NULL;
4475: DMLabel ghostLabel = NULL;
4476: PetscDS ds = NULL;
4477: PetscDS dsAux = NULL;
4478: PetscSection section = NULL;
4479: PetscBool useFEM = PETSC_FALSE;
4480: PetscBool useFVM = PETSC_FALSE;
4481: PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
4482: PetscFV fvm = NULL;
4483: PetscFVCellGeom *cgeomFVM = NULL;
4484: PetscFVFaceGeom *fgeomFVM = NULL;
4485: DMField coordField = NULL;
4486: Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
4487: PetscScalar *u = NULL, *u_t, *a, *uL, *uR;
4488: IS chunkIS;
4489: const PetscInt *cells;
4490: PetscInt cStart, cEnd, numCells;
4491: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
4492: PetscInt maxDegree = PETSC_MAX_INT;
4493: PetscQuadrature affineQuad = NULL, *quads = NULL;
4494: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4496: if (!cellIS) return 0;
4497: PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0);
4498: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4499: /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
4500: /* FEM+FVM */
4501: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4502: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4503: /* 1: Get sizes from dm and dmAux */
4504: DMGetLocalSection(dm, §ion);
4505: DMGetLabel(dm, "ghost", &ghostLabel);
4506: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds);
4507: PetscDSGetNumFields(ds, &Nf);
4508: PetscDSGetTotalDimension(ds, &totDim);
4509: DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA);
4510: if (locA) {
4511: PetscInt subcell;
4512: VecGetDM(locA, &dmAux);
4513: DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell);
4514: DMGetCellDS(dmAux, subcell, &dsAux);
4515: PetscDSGetTotalDimension(dsAux, &totDimAux);
4516: }
4517: /* 2: Get geometric data */
4518: for (f = 0; f < Nf; ++f) {
4519: PetscObject obj;
4520: PetscClassId id;
4521: PetscBool fimp;
4523: PetscDSGetImplicit(ds, f, &fimp);
4524: if (isImplicit != fimp) continue;
4525: PetscDSGetDiscretization(ds, f, &obj);
4526: PetscObjectGetClassId(obj, &id);
4527: if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
4528: if (id == PETSCFV_CLASSID) {
4529: useFVM = PETSC_TRUE;
4530: fvm = (PetscFV)obj;
4531: }
4532: }
4533: if (useFEM) {
4534: DMGetCoordinateField(dm, &coordField);
4535: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4536: if (maxDegree <= 1) {
4537: DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad);
4538: if (affineQuad) DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
4539: } else {
4540: PetscCalloc2(Nf, &quads, Nf, &geoms);
4541: for (f = 0; f < Nf; ++f) {
4542: PetscObject obj;
4543: PetscClassId id;
4544: PetscBool fimp;
4546: PetscDSGetImplicit(ds, f, &fimp);
4547: if (isImplicit != fimp) continue;
4548: PetscDSGetDiscretization(ds, f, &obj);
4549: PetscObjectGetClassId(obj, &id);
4550: if (id == PETSCFE_CLASSID) {
4551: PetscFE fe = (PetscFE)obj;
4553: PetscFEGetQuadrature(fe, &quads[f]);
4554: PetscObjectReference((PetscObject)quads[f]);
4555: DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
4556: }
4557: }
4558: }
4559: }
4560: if (useFVM) {
4561: DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);
4562: VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM);
4563: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM);
4564: /* Reconstruct and limit cell gradients */
4565: DMPlexGetGradientDM(dm, fvm, &dmGrad);
4566: if (dmGrad) {
4567: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4568: DMGetGlobalVector(dmGrad, &grad);
4569: DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
4570: /* Communicate gradient values */
4571: DMGetLocalVector(dmGrad, &locGrad);
4572: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
4573: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
4574: DMRestoreGlobalVector(dmGrad, &grad);
4575: }
4576: /* Handle non-essential (e.g. outflow) boundary values */
4577: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);
4578: }
4579: /* Loop over chunks */
4580: if (useFEM) ISCreate(PETSC_COMM_SELF, &chunkIS);
4581: numCells = cEnd - cStart;
4582: numChunks = 1;
4583: cellChunkSize = numCells / numChunks;
4584: faceChunkSize = (fEnd - fStart) / numChunks;
4585: numChunks = PetscMin(1, numCells);
4586: for (chunk = 0; chunk < numChunks; ++chunk) {
4587: PetscScalar *elemVec, *fluxL, *fluxR;
4588: PetscReal *vol;
4589: PetscFVFaceGeom *fgeom;
4590: PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
4591: PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face;
4593: /* Extract field coefficients */
4594: if (useFEM) {
4595: ISGetPointSubrange(chunkIS, cS, cE, cells);
4596: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4597: DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec);
4598: PetscArrayzero(elemVec, numCells * totDim);
4599: }
4600: if (useFVM) {
4601: DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4602: DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4603: DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL);
4604: DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR);
4605: PetscArrayzero(fluxL, numFaces * totDim);
4606: PetscArrayzero(fluxR, numFaces * totDim);
4607: }
4608: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
4609: /* Loop over fields */
4610: for (f = 0; f < Nf; ++f) {
4611: PetscObject obj;
4612: PetscClassId id;
4613: PetscBool fimp;
4614: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
4616: key.field = f;
4617: PetscDSGetImplicit(ds, f, &fimp);
4618: if (isImplicit != fimp) continue;
4619: PetscDSGetDiscretization(ds, f, &obj);
4620: PetscObjectGetClassId(obj, &id);
4621: if (id == PETSCFE_CLASSID) {
4622: PetscFE fe = (PetscFE)obj;
4623: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4624: PetscFEGeom *chunkGeom = NULL;
4625: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4626: PetscInt Nq, Nb;
4628: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4629: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4630: PetscFEGetDimension(fe, &Nb);
4631: blockSize = Nb;
4632: batchSize = numBlocks * blockSize;
4633: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4634: numChunks = numCells / (numBatches * batchSize);
4635: Ne = numChunks * numBatches * batchSize;
4636: Nr = numCells % (numBatches * batchSize);
4637: offset = numCells - Nr;
4638: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4639: /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */
4640: PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom);
4641: PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec);
4642: PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom);
4643: PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, &a[offset * totDimAux], t, &elemVec[offset * totDim]);
4644: PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom);
4645: } else if (id == PETSCFV_CLASSID) {
4646: PetscFV fv = (PetscFV)obj;
4648: Ne = numFaces;
4649: /* Riemann solve over faces (need fields at face centroids) */
4650: /* We need to evaluate FE fields at those coordinates */
4651: PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4652: } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
4653: }
4654: /* Loop over domain */
4655: if (useFEM) {
4656: /* Add elemVec to locX */
4657: for (c = cS; c < cE; ++c) {
4658: const PetscInt cell = cells ? cells[c] : c;
4659: const PetscInt cind = c - cStart;
4661: if (mesh->printFEM > 1) DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]);
4662: if (ghostLabel) {
4663: PetscInt ghostVal;
4665: DMLabelGetValue(ghostLabel, cell, &ghostVal);
4666: if (ghostVal > 0) continue;
4667: }
4668: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES);
4669: }
4670: }
4671: if (useFVM) {
4672: PetscScalar *fa;
4673: PetscInt iface;
4675: VecGetArray(locF, &fa);
4676: for (f = 0; f < Nf; ++f) {
4677: PetscFV fv;
4678: PetscObject obj;
4679: PetscClassId id;
4680: PetscInt foff, pdim;
4682: PetscDSGetDiscretization(ds, f, &obj);
4683: PetscDSGetFieldOffset(ds, f, &foff);
4684: PetscObjectGetClassId(obj, &id);
4685: if (id != PETSCFV_CLASSID) continue;
4686: fv = (PetscFV)obj;
4687: PetscFVGetNumComponents(fv, &pdim);
4688: /* Accumulate fluxes to cells */
4689: for (face = fS, iface = 0; face < fE; ++face) {
4690: const PetscInt *scells;
4691: PetscScalar *fL = NULL, *fR = NULL;
4692: PetscInt ghost, d, nsupp, nchild;
4694: DMLabelGetValue(ghostLabel, face, &ghost);
4695: DMPlexGetSupportSize(dm, face, &nsupp);
4696: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4697: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4698: DMPlexGetSupport(dm, face, &scells);
4699: DMLabelGetValue(ghostLabel, scells[0], &ghost);
4700: if (ghost <= 0) DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);
4701: DMLabelGetValue(ghostLabel, scells[1], &ghost);
4702: if (ghost <= 0) DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);
4703: for (d = 0; d < pdim; ++d) {
4704: if (fL) fL[d] -= fluxL[iface * totDim + foff + d];
4705: if (fR) fR[d] += fluxR[iface * totDim + foff + d];
4706: }
4707: ++iface;
4708: }
4709: }
4710: VecRestoreArray(locF, &fa);
4711: }
4712: /* Handle time derivative */
4713: if (locX_t) {
4714: PetscScalar *x_t, *fa;
4716: VecGetArray(locF, &fa);
4717: VecGetArray(locX_t, &x_t);
4718: for (f = 0; f < Nf; ++f) {
4719: PetscFV fv;
4720: PetscObject obj;
4721: PetscClassId id;
4722: PetscInt pdim, d;
4724: PetscDSGetDiscretization(ds, f, &obj);
4725: PetscObjectGetClassId(obj, &id);
4726: if (id != PETSCFV_CLASSID) continue;
4727: fv = (PetscFV)obj;
4728: PetscFVGetNumComponents(fv, &pdim);
4729: for (c = cS; c < cE; ++c) {
4730: const PetscInt cell = cells ? cells[c] : c;
4731: PetscScalar *u_t, *r;
4733: if (ghostLabel) {
4734: PetscInt ghostVal;
4736: DMLabelGetValue(ghostLabel, cell, &ghostVal);
4737: if (ghostVal > 0) continue;
4738: }
4739: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4740: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4741: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4742: }
4743: }
4744: VecRestoreArray(locX_t, &x_t);
4745: VecRestoreArray(locF, &fa);
4746: }
4747: if (useFEM) {
4748: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4749: DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec);
4750: }
4751: if (useFVM) {
4752: DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4753: DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4754: DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL);
4755: DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR);
4756: if (dmGrad) DMRestoreLocalVector(dmGrad, &locGrad);
4757: }
4758: }
4759: if (useFEM) ISDestroy(&chunkIS);
4760: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
4762: if (useFEM) {
4763: DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);
4765: if (maxDegree <= 1) {
4766: DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
4767: PetscQuadratureDestroy(&affineQuad);
4768: } else {
4769: for (f = 0; f < Nf; ++f) {
4770: DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
4771: PetscQuadratureDestroy(&quads[f]);
4772: }
4773: PetscFree2(quads, geoms);
4774: }
4775: }
4777: /* FEM */
4778: /* 1: Get sizes from dm and dmAux */
4779: /* 2: Get geometric data */
4780: /* 3: Handle boundary values */
4781: /* 4: Loop over domain */
4782: /* Extract coefficients */
4783: /* Loop over fields */
4784: /* Set tiling for FE*/
4785: /* Integrate FE residual to get elemVec */
4786: /* Loop over subdomain */
4787: /* Loop over quad points */
4788: /* Transform coords to real space */
4789: /* Evaluate field and aux fields at point */
4790: /* Evaluate residual at point */
4791: /* Transform residual to real space */
4792: /* Add residual to elemVec */
4793: /* Loop over domain */
4794: /* Add elemVec to locX */
4796: /* FVM */
4797: /* Get geometric data */
4798: /* If using gradients */
4799: /* Compute gradient data */
4800: /* Loop over domain faces */
4801: /* Count computational faces */
4802: /* Reconstruct cell gradient */
4803: /* Loop over domain cells */
4804: /* Limit cell gradients */
4805: /* Handle boundary values */
4806: /* Loop over domain faces */
4807: /* Read out field, centroid, normal, volume for each side of face */
4808: /* Riemann solve over faces */
4809: /* Loop over domain faces */
4810: /* Accumulate fluxes to cells */
4811: /* TODO Change printFEM to printDisc here */
4812: if (mesh->printFEM) {
4813: Vec locFbc;
4814: PetscInt pStart, pEnd, p, maxDof;
4815: PetscScalar *zeroes;
4817: VecDuplicate(locF, &locFbc);
4818: VecCopy(locF, locFbc);
4819: PetscSectionGetChart(section, &pStart, &pEnd);
4820: PetscSectionGetMaxDof(section, &maxDof);
4821: PetscCalloc1(maxDof, &zeroes);
4822: for (p = pStart; p < pEnd; p++) VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES);
4823: PetscFree(zeroes);
4824: DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4825: VecDestroy(&locFbc);
4826: }
4827: PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0);
4828: return 0;
4829: }
4831: /*
4832: 1) Allow multiple kernels for BdResidual for hybrid DS
4834: DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux
4836: DONE 3) Change DMGetCellFields() to get different aux data a[] for each side
4837: - I think I just need to replace a[] with the closure from each face
4839: 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before
4840: */
4841: PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4842: {
4843: DM_Plex *mesh = (DM_Plex *)dm->data;
4844: const char *name = "Hybrid Residual";
4845: DM dmAux[3] = {NULL, NULL, NULL};
4846: DMLabel ghostLabel = NULL;
4847: PetscDS ds = NULL;
4848: PetscDS dsAux[3] = {NULL, NULL, NULL};
4849: Vec locA[3] = {NULL, NULL, NULL};
4850: PetscScalar *a[3] = {NULL, NULL, NULL};
4851: PetscSection section = NULL;
4852: DMField coordField = NULL;
4853: PetscScalar *u = NULL, *u_t;
4854: PetscScalar *elemVec;
4855: IS chunkIS;
4856: const PetscInt *cells;
4857: PetscInt *faces;
4858: PetscInt cStart, cEnd, numCells;
4859: PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
4860: PetscInt maxDegree = PETSC_MAX_INT;
4861: PetscQuadrature affineQuad = NULL, *quads = NULL;
4862: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4864: if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
4865: const char *name;
4866: PetscObjectGetName((PetscObject)key[0].label, &name);
4867: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part);
4868: }
4869: PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0);
4870: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4871: /* FEM */
4872: ISGetLocalSize(cellIS, &numCells);
4873: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4874: /* 1: Get sizes from dm and dmAux */
4875: DMGetSection(dm, §ion);
4876: DMGetLabel(dm, "ghost", &ghostLabel);
4877: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds);
4878: PetscDSGetNumFields(ds, &Nf);
4879: PetscDSGetTotalDimension(ds, &totDim);
4880: DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]);
4881: if (locA[2]) {
4882: const PetscInt cellStart = cells ? cells[cStart] : cStart;
4884: VecGetDM(locA[2], &dmAux[2]);
4885: DMGetCellDS(dmAux[2], cellStart, &dsAux[2]);
4886: PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
4887: {
4888: const PetscInt *cone;
4889: PetscInt c;
4891: DMPlexGetCone(dm, cellStart, &cone);
4892: for (c = 0; c < 2; ++c) {
4893: const PetscInt *support;
4894: PetscInt ssize, s;
4896: DMPlexGetSupport(dm, cone[c], &support);
4897: DMPlexGetSupportSize(dm, cone[c], &ssize);
4899: if (support[0] == cellStart) s = 1;
4900: else if (support[1] == cellStart) s = 0;
4901: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart);
4902: DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]);
4904: if (locA[c]) VecGetDM(locA[c], &dmAux[c]);
4905: else dmAux[c] = dmAux[2];
4906: DMGetCellDS(dmAux[c], support[s], &dsAux[c]);
4907: PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
4908: }
4909: }
4910: }
4911: /* 2: Setup geometric data */
4912: DMGetCoordinateField(dm, &coordField);
4913: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4914: if (maxDegree > 1) {
4915: PetscCalloc2(Nf, &quads, Nf, &geoms);
4916: for (f = 0; f < Nf; ++f) {
4917: PetscFE fe;
4919: PetscDSGetDiscretization(ds, f, (PetscObject *)&fe);
4920: if (fe) {
4921: PetscFEGetQuadrature(fe, &quads[f]);
4922: PetscObjectReference((PetscObject)quads[f]);
4923: }
4924: }
4925: }
4926: /* Loop over chunks */
4927: cellChunkSize = numCells;
4928: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
4929: PetscCalloc1(1 * cellChunkSize, &faces);
4930: ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4931: /* Extract field coefficients */
4932: /* NOTE This needs the end cap faces to have identical orientations */
4933: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
4934: DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a);
4935: DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVec);
4936: for (chunk = 0; chunk < numChunks; ++chunk) {
4937: PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
4939: PetscMemzero(elemVec, cellChunkSize * totDim * sizeof(PetscScalar));
4940: /* Get faces */
4941: for (c = cS; c < cE; ++c) {
4942: const PetscInt cell = cells ? cells[c] : c;
4943: const PetscInt *cone;
4944: DMPlexGetCone(dm, cell, &cone);
4945: faces[0 * cellChunkSize + (c - cS)] = cone[0];
4946: /*faces[1*cellChunkSize+(c-cS)] = cone[1];*/
4947: }
4948: ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER);
4949: /* Get geometric data */
4950: if (maxDegree <= 1) {
4951: if (!affineQuad) DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);
4952: if (affineQuad) DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);
4953: } else {
4954: for (f = 0; f < Nf; ++f) {
4955: if (quads[f]) DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);
4956: }
4957: }
4958: /* Loop over fields */
4959: for (f = 0; f < Nf; ++f) {
4960: PetscFE fe;
4961: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4962: PetscFEGeom *chunkGeom = NULL, *remGeom = NULL;
4963: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4964: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
4965: PetscBool isCohesiveField;
4967: PetscDSGetDiscretization(ds, f, (PetscObject *)&fe);
4968: if (!fe) continue;
4969: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4970: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4971: PetscFEGetDimension(fe, &Nb);
4972: blockSize = Nb;
4973: batchSize = numBlocks * blockSize;
4974: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4975: numChunks = numCells / (numBatches * batchSize);
4976: Ne = numChunks * numBatches * batchSize;
4977: Nr = numCells % (numBatches * batchSize);
4978: offset = numCells - Nr;
4979: PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom);
4980: PetscFEGeomGetChunk(geom, offset, numCells, &remGeom);
4981: PetscDSGetCohesive(ds, f, &isCohesiveField);
4982: chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE;
4983: key[0].field = f;
4984: key[1].field = f;
4985: key[2].field = f;
4986: PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec);
4987: PetscFEIntegrateHybridResidual(ds, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVec[offset * totDim]);
4988: PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec);
4989: PetscFEIntegrateHybridResidual(ds, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVec[offset * totDim]);
4990: PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec);
4991: PetscFEIntegrateHybridResidual(ds, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVec[offset * totDim]);
4992: PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom);
4993: PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom);
4994: }
4995: /* Add elemVec to locX */
4996: for (c = cS; c < cE; ++c) {
4997: const PetscInt cell = cells ? cells[c] : c;
4998: const PetscInt cind = c - cStart;
5000: if (mesh->printFEM > 1) DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]);
5001: if (ghostLabel) {
5002: PetscInt ghostVal;
5004: DMLabelGetValue(ghostLabel, cell, &ghostVal);
5005: if (ghostVal > 0) continue;
5006: }
5007: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES);
5008: }
5009: }
5010: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5011: DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a);
5012: DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec);
5013: PetscFree(faces);
5014: ISDestroy(&chunkIS);
5015: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5016: if (maxDegree <= 1) {
5017: DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
5018: PetscQuadratureDestroy(&affineQuad);
5019: } else {
5020: for (f = 0; f < Nf; ++f) {
5021: if (geoms) DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
5022: if (quads) PetscQuadratureDestroy(&quads[f]);
5023: }
5024: PetscFree2(quads, geoms);
5025: }
5026: PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0);
5027: return 0;
5028: }
5030: PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP, DMField coordField, IS facetIS)
5031: {
5032: DM_Plex *mesh = (DM_Plex *)dm->data;
5033: DM plex = NULL, plexA = NULL, tdm;
5034: DMEnclosureType encAux;
5035: PetscDS prob, probAux = NULL;
5036: PetscSection section, sectionAux = NULL;
5037: PetscSection globalSection;
5038: Vec locA = NULL, tv;
5039: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
5040: PetscInt v;
5041: PetscInt Nf, totDim, totDimAux = 0;
5042: PetscBool transform;
5044: DMConvert(dm, DMPLEX, &plex);
5045: DMHasBasisTransform(dm, &transform);
5046: DMGetBasisTransformDM_Internal(dm, &tdm);
5047: DMGetBasisTransformVec_Internal(dm, &tv);
5048: DMGetLocalSection(dm, §ion);
5049: DMGetDS(dm, &prob);
5050: PetscDSGetNumFields(prob, &Nf);
5051: PetscDSGetTotalDimension(prob, &totDim);
5052: DMGetAuxiliaryVec(dm, label, values[0], 0, &locA);
5053: if (locA) {
5054: DM dmAux;
5056: VecGetDM(locA, &dmAux);
5057: DMGetEnclosureRelation(dmAux, dm, &encAux);
5058: DMConvert(dmAux, DMPLEX, &plexA);
5059: DMGetDS(plexA, &probAux);
5060: PetscDSGetTotalDimension(probAux, &totDimAux);
5061: DMGetLocalSection(plexA, §ionAux);
5062: }
5064: DMGetGlobalSection(dm, &globalSection);
5065: for (v = 0; v < numValues; ++v) {
5066: PetscFEGeom *fgeom;
5067: PetscInt maxDegree;
5068: PetscQuadrature qGeom = NULL;
5069: IS pointIS;
5070: const PetscInt *points;
5071: PetscFormKey key;
5072: PetscInt numFaces, face, Nq;
5074: key.label = label;
5075: key.value = values[v];
5076: key.part = 0;
5077: DMLabelGetStratumIS(label, values[v], &pointIS);
5078: if (!pointIS) continue; /* No points with that id on this process */
5079: {
5080: IS isectIS;
5082: /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
5083: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
5084: ISDestroy(&pointIS);
5085: pointIS = isectIS;
5086: }
5087: ISGetLocalSize(pointIS, &numFaces);
5088: ISGetIndices(pointIS, &points);
5089: PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a);
5090: DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
5091: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);
5092: if (!qGeom) {
5093: PetscFE fe;
5095: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe);
5096: PetscFEGetFaceQuadrature(fe, &qGeom);
5097: PetscObjectReference((PetscObject)qGeom);
5098: }
5099: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5100: DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
5101: for (face = 0; face < numFaces; ++face) {
5102: const PetscInt point = points[face], *support;
5103: PetscScalar *x = NULL;
5104: PetscInt i;
5106: DMPlexGetSupport(dm, point, &support);
5107: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5108: for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
5109: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5110: if (locX_t) {
5111: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5112: for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
5113: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5114: }
5115: if (locA) {
5116: PetscInt subp;
5117: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5118: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5119: for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
5120: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5121: }
5122: }
5123: PetscArrayzero(elemMat, numFaces * totDim * totDim);
5124: {
5125: PetscFE fe;
5126: PetscInt Nb;
5127: /* Conforming batches */
5128: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5129: /* Remainder */
5130: PetscFEGeom *chunkGeom = NULL;
5131: PetscInt fieldJ, Nr, offset;
5133: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe);
5134: PetscFEGetDimension(fe, &Nb);
5135: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5136: blockSize = Nb;
5137: batchSize = numBlocks * blockSize;
5138: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5139: numChunks = numFaces / (numBatches * batchSize);
5140: Ne = numChunks * numBatches * batchSize;
5141: Nr = numFaces % (numBatches * batchSize);
5142: offset = numFaces - Nr;
5143: PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom);
5144: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5145: key.field = fieldI * Nf + fieldJ;
5146: PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5147: }
5148: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
5149: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5150: key.field = fieldI * Nf + fieldJ;
5151: PetscFEIntegrateBdJacobian(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim]);
5152: }
5153: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
5154: }
5155: for (face = 0; face < numFaces; ++face) {
5156: const PetscInt point = points[face], *support;
5158: /* Transform to global basis before insertion in Jacobian */
5159: DMPlexGetSupport(plex, point, &support);
5160: if (transform) DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim]);
5161: if (mesh->printFEM > 1) DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim]);
5162: DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES);
5163: }
5164: DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
5165: PetscQuadratureDestroy(&qGeom);
5166: ISRestoreIndices(pointIS, &points);
5167: ISDestroy(&pointIS);
5168: PetscFree4(u, u_t, elemMat, a);
5169: }
5170: if (plex) DMDestroy(&plex);
5171: if (plexA) DMDestroy(&plexA);
5172: return 0;
5173: }
5175: PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP)
5176: {
5177: DMField coordField;
5178: DMLabel depthLabel;
5179: IS facetIS;
5180: PetscInt dim;
5182: DMGetDimension(dm, &dim);
5183: DMPlexGetDepthLabel(dm, &depthLabel);
5184: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
5185: DMGetCoordinateField(dm, &coordField);
5186: DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5187: ISDestroy(&facetIS);
5188: return 0;
5189: }
5191: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5192: {
5193: PetscDS prob;
5194: PetscInt dim, numBd, bd;
5195: DMLabel depthLabel;
5196: DMField coordField = NULL;
5197: IS facetIS;
5199: DMGetDS(dm, &prob);
5200: DMPlexGetDepthLabel(dm, &depthLabel);
5201: DMGetDimension(dm, &dim);
5202: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
5203: PetscDSGetNumBoundary(prob, &numBd);
5204: DMGetCoordinateField(dm, &coordField);
5205: for (bd = 0; bd < numBd; ++bd) {
5206: PetscWeakForm wf;
5207: DMBoundaryConditionType type;
5208: DMLabel label;
5209: const PetscInt *values;
5210: PetscInt fieldI, numValues;
5211: PetscObject obj;
5212: PetscClassId id;
5214: PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL);
5215: if (type & DM_BC_ESSENTIAL) continue;
5216: PetscDSGetDiscretization(prob, fieldI, &obj);
5217: PetscObjectGetClassId(obj, &id);
5218: if (id != PETSCFE_CLASSID) continue;
5219: DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5220: }
5221: ISDestroy(&facetIS);
5222: return 0;
5223: }
5225: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *user)
5226: {
5227: DM_Plex *mesh = (DM_Plex *)dm->data;
5228: const char *name = "Jacobian";
5229: DM dmAux = NULL, plex, tdm;
5230: DMEnclosureType encAux;
5231: Vec A, tv;
5232: DMField coordField;
5233: PetscDS prob, probAux = NULL;
5234: PetscSection section, globalSection, sectionAux;
5235: PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5236: const PetscInt *cells;
5237: PetscInt Nf, fieldI, fieldJ;
5238: PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c;
5239: PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform;
5241: if (!cellIS) goto end;
5242: PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5243: ISGetLocalSize(cellIS, &numCells);
5244: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5245: DMHasBasisTransform(dm, &transform);
5246: DMGetBasisTransformDM_Internal(dm, &tdm);
5247: DMGetBasisTransformVec_Internal(dm, &tv);
5248: DMGetLocalSection(dm, §ion);
5249: DMGetGlobalSection(dm, &globalSection);
5250: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5251: PetscDSGetNumFields(prob, &Nf);
5252: PetscDSGetTotalDimension(prob, &totDim);
5253: PetscDSHasJacobian(prob, &hasJac);
5254: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
5255: /* user passed in the same matrix, avoid double contributions and
5256: only assemble the Jacobian */
5257: if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
5258: PetscDSHasDynamicJacobian(prob, &hasDyn);
5259: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5260: DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A);
5261: if (A) {
5262: VecGetDM(A, &dmAux);
5263: DMGetEnclosureRelation(dmAux, dm, &encAux);
5264: DMConvert(dmAux, DMPLEX, &plex);
5265: DMGetLocalSection(plex, §ionAux);
5266: DMGetDS(dmAux, &probAux);
5267: PetscDSGetTotalDimension(probAux, &totDimAux);
5268: }
5269: PetscMalloc5(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, hasJac ? numCells * totDim * totDim : 0, &elemMat, hasPrec ? numCells * totDim * totDim : 0, &elemMatP, hasDyn ? numCells * totDim * totDim : 0, &elemMatD);
5270: if (dmAux) PetscMalloc1(numCells * totDimAux, &a);
5271: DMGetCoordinateField(dm, &coordField);
5272: for (c = cStart; c < cEnd; ++c) {
5273: const PetscInt cell = cells ? cells[c] : c;
5274: const PetscInt cind = c - cStart;
5275: PetscScalar *x = NULL, *x_t = NULL;
5276: PetscInt i;
5278: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5279: for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
5280: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5281: if (X_t) {
5282: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5283: for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
5284: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5285: }
5286: if (dmAux) {
5287: PetscInt subcell;
5288: DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5289: DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5290: for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
5291: DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5292: }
5293: }
5294: if (hasJac) PetscArrayzero(elemMat, numCells * totDim * totDim);
5295: if (hasPrec) PetscArrayzero(elemMatP, numCells * totDim * totDim);
5296: if (hasDyn) PetscArrayzero(elemMatD, numCells * totDim * totDim);
5297: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5298: PetscClassId id;
5299: PetscFE fe;
5300: PetscQuadrature qGeom = NULL;
5301: PetscInt Nb;
5302: /* Conforming batches */
5303: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5304: /* Remainder */
5305: PetscInt Nr, offset, Nq;
5306: PetscInt maxDegree;
5307: PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
5309: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe);
5310: PetscObjectGetClassId((PetscObject)fe, &id);
5311: if (id == PETSCFV_CLASSID) {
5312: hasFV = PETSC_TRUE;
5313: continue;
5314: }
5315: PetscFEGetDimension(fe, &Nb);
5316: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5317: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5318: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);
5319: if (!qGeom) {
5320: PetscFEGetQuadrature(fe, &qGeom);
5321: PetscObjectReference((PetscObject)qGeom);
5322: }
5323: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5324: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
5325: blockSize = Nb;
5326: batchSize = numBlocks * blockSize;
5327: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5328: numChunks = numCells / (numBatches * batchSize);
5329: Ne = numChunks * numBatches * batchSize;
5330: Nr = numCells % (numBatches * batchSize);
5331: offset = numCells - Nr;
5332: PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom);
5333: PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom);
5334: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5335: key.field = fieldI * Nf + fieldJ;
5336: if (hasJac) {
5337: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5338: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim]);
5339: }
5340: if (hasPrec) {
5341: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5342: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatP[offset * totDim * totDim]);
5343: }
5344: if (hasDyn) {
5345: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5346: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim]);
5347: }
5348: }
5349: PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom);
5350: PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom);
5351: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
5352: PetscQuadratureDestroy(&qGeom);
5353: }
5354: /* Add contribution from X_t */
5355: if (hasDyn) {
5356: for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
5357: }
5358: if (hasFV) {
5359: PetscClassId id;
5360: PetscFV fv;
5361: PetscInt offsetI, NcI, NbI = 1, fc, f;
5363: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5364: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv);
5365: PetscDSGetFieldOffset(prob, fieldI, &offsetI);
5366: PetscObjectGetClassId((PetscObject)fv, &id);
5367: if (id != PETSCFV_CLASSID) continue;
5368: /* Put in the identity */
5369: PetscFVGetNumComponents(fv, &NcI);
5370: for (c = cStart; c < cEnd; ++c) {
5371: const PetscInt cind = c - cStart;
5372: const PetscInt eOffset = cind * totDim * totDim;
5373: for (fc = 0; fc < NcI; ++fc) {
5374: for (f = 0; f < NbI; ++f) {
5375: const PetscInt i = offsetI + f * NcI + fc;
5376: if (hasPrec) {
5377: if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
5378: elemMatP[eOffset + i * totDim + i] = 1.0;
5379: } else {
5380: elemMat[eOffset + i * totDim + i] = 1.0;
5381: }
5382: }
5383: }
5384: }
5385: }
5386: /* No allocated space for FV stuff, so ignore the zero entries */
5387: MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);
5388: }
5389: /* Insert values into matrix */
5390: for (c = cStart; c < cEnd; ++c) {
5391: const PetscInt cell = cells ? cells[c] : c;
5392: const PetscInt cind = c - cStart;
5394: /* Transform to global basis before insertion in Jacobian */
5395: if (transform) DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim]);
5396: if (hasPrec) {
5397: if (hasJac) {
5398: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]);
5399: DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES);
5400: }
5401: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]);
5402: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES);
5403: } else {
5404: if (hasJac) {
5405: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]);
5406: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES);
5407: }
5408: }
5409: }
5410: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5411: if (hasFV) MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);
5412: PetscFree5(u, u_t, elemMat, elemMatP, elemMatD);
5413: if (dmAux) {
5414: PetscFree(a);
5415: DMDestroy(&plex);
5416: }
5417: /* Compute boundary integrals */
5418: DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5419: /* Assemble matrix */
5420: end : {
5421: PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp;
5423: MPI_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm));
5424: if (hasJac && hasPrec) {
5425: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5426: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5427: }
5428: }
5429: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5430: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5431: PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5432: return 0;
5433: }
5435: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5436: {
5437: DM_Plex *mesh = (DM_Plex *)dm->data;
5438: const char *name = "Hybrid Jacobian";
5439: DM dmAux[3] = {NULL, NULL, NULL};
5440: DMLabel ghostLabel = NULL;
5441: DM plex = NULL;
5442: DM plexA = NULL;
5443: PetscDS ds = NULL;
5444: PetscDS dsAux[3] = {NULL, NULL, NULL};
5445: Vec locA[3] = {NULL, NULL, NULL};
5446: PetscSection section = NULL;
5447: PetscSection sectionAux[3] = {NULL, NULL, NULL};
5448: DMField coordField = NULL;
5449: PetscScalar *u = NULL, *u_t, *a[3];
5450: PetscScalar *elemMat, *elemMatP;
5451: PetscSection globalSection;
5452: IS chunkIS;
5453: const PetscInt *cells;
5454: PetscInt *faces;
5455: PetscInt cStart, cEnd, numCells;
5456: PetscInt Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
5457: PetscInt maxDegree = PETSC_MAX_INT;
5458: PetscQuadrature affineQuad = NULL, *quads = NULL;
5459: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
5460: PetscBool hasBdJac, hasBdPrec;
5462: if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
5463: const char *name;
5464: PetscObjectGetName((PetscObject)key[0].label, &name);
5465: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part);
5466: }
5467: PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5468: ISGetLocalSize(cellIS, &numCells);
5469: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5470: DMConvert(dm, DMPLEX, &plex);
5471: DMGetSection(dm, §ion);
5472: DMGetGlobalSection(dm, &globalSection);
5473: DMGetLabel(dm, "ghost", &ghostLabel);
5474: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds);
5475: PetscDSGetNumFields(ds, &Nf);
5476: PetscDSGetTotalDimension(ds, &totDim);
5477: PetscDSHasBdJacobian(ds, &hasBdJac);
5478: PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec);
5479: DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]);
5480: if (locA[2]) {
5481: const PetscInt cellStart = cells ? cells[cStart] : cStart;
5483: VecGetDM(locA[2], &dmAux[2]);
5484: DMConvert(dmAux[2], DMPLEX, &plexA);
5485: DMGetSection(dmAux[2], §ionAux[2]);
5486: DMGetCellDS(dmAux[2], cellStart, &dsAux[2]);
5487: PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
5488: {
5489: const PetscInt *cone;
5490: PetscInt c;
5492: DMPlexGetCone(dm, cellStart, &cone);
5493: for (c = 0; c < 2; ++c) {
5494: const PetscInt *support;
5495: PetscInt ssize, s;
5497: DMPlexGetSupport(dm, cone[c], &support);
5498: DMPlexGetSupportSize(dm, cone[c], &ssize);
5500: if (support[0] == cellStart) s = 1;
5501: else if (support[1] == cellStart) s = 0;
5502: else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart);
5503: DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]);
5504: if (locA[c]) VecGetDM(locA[c], &dmAux[c]);
5505: else dmAux[c] = dmAux[2];
5506: DMGetCellDS(dmAux[c], support[s], &dsAux[c]);
5507: PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
5508: }
5509: }
5510: }
5511: DMGetCoordinateField(dm, &coordField);
5512: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5513: if (maxDegree > 1) {
5514: PetscInt f;
5515: PetscCalloc2(Nf, &quads, Nf, &geoms);
5516: for (f = 0; f < Nf; ++f) {
5517: PetscFE fe;
5519: PetscDSGetDiscretization(ds, f, (PetscObject *)&fe);
5520: if (fe) {
5521: PetscFEGetQuadrature(fe, &quads[f]);
5522: PetscObjectReference((PetscObject)quads[f]);
5523: }
5524: }
5525: }
5526: cellChunkSize = numCells;
5527: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
5528: PetscCalloc1(1 * cellChunkSize, &faces);
5529: ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5530: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5531: DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a);
5532: DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat);
5533: DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP);
5534: for (chunk = 0; chunk < numChunks; ++chunk) {
5535: PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
5537: if (hasBdJac) PetscMemzero(elemMat, numCells * totDim * totDim * sizeof(PetscScalar));
5538: if (hasBdPrec) PetscMemzero(elemMatP, numCells * totDim * totDim * sizeof(PetscScalar));
5539: /* Get faces */
5540: for (c = cS; c < cE; ++c) {
5541: const PetscInt cell = cells ? cells[c] : c;
5542: const PetscInt *cone;
5543: DMPlexGetCone(plex, cell, &cone);
5544: faces[0 * cellChunkSize + (c - cS)] = cone[0];
5545: /*faces[2*cellChunkSize+(c-cS)] = cone[1];*/
5546: }
5547: ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER);
5548: if (maxDegree <= 1) {
5549: if (!affineQuad) DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);
5550: if (affineQuad) DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);
5551: } else {
5552: PetscInt f;
5553: for (f = 0; f < Nf; ++f) {
5554: if (quads[f]) DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);
5555: }
5556: }
5558: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5559: PetscFE feI;
5560: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI];
5561: PetscFEGeom *chunkGeom = NULL, *remGeom = NULL;
5562: PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5563: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
5564: PetscBool isCohesiveField;
5566: PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI);
5567: if (!feI) continue;
5568: PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5569: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5570: PetscFEGetDimension(feI, &Nb);
5571: blockSize = Nb;
5572: batchSize = numBlocks * blockSize;
5573: PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5574: numChunks = numCells / (numBatches * batchSize);
5575: Ne = numChunks * numBatches * batchSize;
5576: Nr = numCells % (numBatches * batchSize);
5577: offset = numCells - Nr;
5578: PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom);
5579: PetscFEGeomGetChunk(geom, offset, numCells, &remGeom);
5580: PetscDSGetCohesive(ds, fieldI, &isCohesiveField);
5581: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5582: PetscFE feJ;
5584: PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ);
5585: if (!feJ) continue;
5586: key[0].field = fieldI * Nf + fieldJ;
5587: key[1].field = fieldI * Nf + fieldJ;
5588: key[2].field = fieldI * Nf + fieldJ;
5589: if (hasBdJac) {
5590: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat);
5591: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMat[offset * totDim * totDim]);
5592: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat);
5593: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMat[offset * totDim * totDim]);
5594: }
5595: if (hasBdPrec) {
5596: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP);
5597: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatP[offset * totDim * totDim]);
5598: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP);
5599: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatP[offset * totDim * totDim]);
5600: }
5601: if (hasBdJac) {
5602: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat);
5603: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMat[offset * totDim * totDim]);
5604: }
5605: if (hasBdPrec) {
5606: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP);
5607: PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatP[offset * totDim * totDim]);
5608: }
5609: }
5610: PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom);
5611: PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom);
5612: }
5613: /* Insert values into matrix */
5614: for (c = cS; c < cE; ++c) {
5615: const PetscInt cell = cells ? cells[c] : c;
5616: const PetscInt cind = c - cS;
5618: if (hasBdPrec) {
5619: if (hasBdJac) {
5620: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]);
5621: DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES);
5622: }
5623: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]);
5624: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES);
5625: } else if (hasBdJac) {
5626: if (mesh->printFEM > 1) DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]);
5627: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES);
5628: }
5629: }
5630: }
5631: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5632: DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a);
5633: DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat);
5634: DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP);
5635: PetscFree(faces);
5636: ISDestroy(&chunkIS);
5637: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5638: if (maxDegree <= 1) {
5639: DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom);
5640: PetscQuadratureDestroy(&affineQuad);
5641: } else {
5642: PetscInt f;
5643: for (f = 0; f < Nf; ++f) {
5644: if (geoms) DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]);
5645: if (quads) PetscQuadratureDestroy(&quads[f]);
5646: }
5647: PetscFree2(quads, geoms);
5648: }
5649: if (dmAux[2]) DMDestroy(&plexA);
5650: DMDestroy(&plex);
5651: PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5652: return 0;
5653: }
5655: /*
5656: DMPlexComputeJacobian_Action_Internal - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user.
5658: Input Parameters:
5659: + dm - The mesh
5660: . key - The PetscWeakFormKey indcating where integration should happen
5661: . cellIS - The cells to integrate over
5662: . t - The time
5663: . X_tShift - The multiplier for the Jacobian with repsect to X_t
5664: . X - Local solution vector
5665: . X_t - Time-derivative of the local solution vector
5666: . Y - Local input vector
5667: - user - the user context
5669: Output Parameter:
5670: . Z - Local output vector
5672: Note:
5673: We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
5674: like a GPU, or vectorize on a multicore machine.
5675: */
5676: PetscErrorCode DMPlexComputeJacobian_Action_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user)
5677: {
5678: DM_Plex *mesh = (DM_Plex *)dm->data;
5679: const char *name = "Jacobian";
5680: DM dmAux = NULL, plex, plexAux = NULL;
5681: DMEnclosureType encAux;
5682: Vec A;
5683: DMField coordField;
5684: PetscDS prob, probAux = NULL;
5685: PetscQuadrature quad;
5686: PetscSection section, globalSection, sectionAux;
5687: PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
5688: const PetscInt *cells;
5689: PetscInt Nf, fieldI, fieldJ;
5690: PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c;
5691: PetscBool hasDyn;
5693: PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5694: DMConvert(dm, DMPLEX, &plex);
5695: if (!cellIS) {
5696: PetscInt depth;
5698: DMPlexGetDepth(plex, &depth);
5699: DMGetStratumIS(plex, "dim", depth, &cellIS);
5700: if (!cellIS) DMGetStratumIS(plex, "depth", depth, &cellIS);
5701: } else {
5702: PetscObjectReference((PetscObject)cellIS);
5703: }
5704: ISGetLocalSize(cellIS, &numCells);
5705: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5706: DMGetLocalSection(dm, §ion);
5707: DMGetGlobalSection(dm, &globalSection);
5708: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5709: PetscDSGetNumFields(prob, &Nf);
5710: PetscDSGetTotalDimension(prob, &totDim);
5711: PetscDSHasDynamicJacobian(prob, &hasDyn);
5712: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5713: DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A);
5714: if (A) {
5715: VecGetDM(A, &dmAux);
5716: DMGetEnclosureRelation(dmAux, dm, &encAux);
5717: DMConvert(dmAux, DMPLEX, &plexAux);
5718: DMGetLocalSection(plexAux, §ionAux);
5719: DMGetDS(dmAux, &probAux);
5720: PetscDSGetTotalDimension(probAux, &totDimAux);
5721: }
5722: VecSet(Z, 0.0);
5723: PetscMalloc6(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, numCells * totDim * totDim, &elemMat, hasDyn ? numCells * totDim * totDim : 0, &elemMatD, numCells * totDim, &y, totDim, &z);
5724: if (dmAux) PetscMalloc1(numCells * totDimAux, &a);
5725: DMGetCoordinateField(dm, &coordField);
5726: for (c = cStart; c < cEnd; ++c) {
5727: const PetscInt cell = cells ? cells[c] : c;
5728: const PetscInt cind = c - cStart;
5729: PetscScalar *x = NULL, *x_t = NULL;
5730: PetscInt i;
5732: DMPlexVecGetClosure(plex, section, X, cell, NULL, &x);
5733: for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
5734: DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x);
5735: if (X_t) {
5736: DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t);
5737: for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
5738: DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t);
5739: }
5740: if (dmAux) {
5741: PetscInt subcell;
5742: DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5743: DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x);
5744: for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
5745: DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x);
5746: }
5747: DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x);
5748: for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i];
5749: DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x);
5750: }
5751: PetscArrayzero(elemMat, numCells * totDim * totDim);
5752: if (hasDyn) PetscArrayzero(elemMatD, numCells * totDim * totDim);
5753: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5754: PetscFE fe;
5755: PetscInt Nb;
5756: /* Conforming batches */
5757: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5758: /* Remainder */
5759: PetscInt Nr, offset, Nq;
5760: PetscQuadrature qGeom = NULL;
5761: PetscInt maxDegree;
5762: PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
5764: PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe);
5765: PetscFEGetQuadrature(fe, &quad);
5766: PetscFEGetDimension(fe, &Nb);
5767: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5768: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5769: if (maxDegree <= 1) DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);
5770: if (!qGeom) {
5771: PetscFEGetQuadrature(fe, &qGeom);
5772: PetscObjectReference((PetscObject)qGeom);
5773: }
5774: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5775: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
5776: blockSize = Nb;
5777: batchSize = numBlocks * blockSize;
5778: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5779: numChunks = numCells / (numBatches * batchSize);
5780: Ne = numChunks * numBatches * batchSize;
5781: Nr = numCells % (numBatches * batchSize);
5782: offset = numCells - Nr;
5783: PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom);
5784: PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom);
5785: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5786: key.field = fieldI * Nf + fieldJ;
5787: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5788: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim]);
5789: if (hasDyn) {
5790: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5791: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim]);
5792: }
5793: }
5794: PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom);
5795: PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom);
5796: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
5797: PetscQuadratureDestroy(&qGeom);
5798: }
5799: if (hasDyn) {
5800: for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
5801: }
5802: for (c = cStart; c < cEnd; ++c) {
5803: const PetscInt cell = cells ? cells[c] : c;
5804: const PetscInt cind = c - cStart;
5805: const PetscBLASInt M = totDim, one = 1;
5806: const PetscScalar a = 1.0, b = 0.0;
5808: PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one));
5809: if (mesh->printFEM > 1) {
5810: DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim]);
5811: DMPrintCellVector(c, "Y", totDim, &y[cind * totDim]);
5812: DMPrintCellVector(c, "Z", totDim, z);
5813: }
5814: DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES);
5815: }
5816: PetscFree6(u, u_t, elemMat, elemMatD, y, z);
5817: if (mesh->printFEM) {
5818: PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n");
5819: VecView(Z, NULL);
5820: }
5821: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5822: PetscFree(a);
5823: ISDestroy(&cellIS);
5824: DMDestroy(&plexAux);
5825: DMDestroy(&plex);
5826: PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0);
5827: return 0;
5828: }