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