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