Actual source code: plexfem.c
petsc-master 2020-08-25
1: #include <petsc/private/dmpleximpl.h>
2: #include <petscsf.h>
4: #include <petsc/private/hashsetij.h>
5: #include <petsc/private/petscfeimpl.h>
6: #include <petsc/private/petscfvimpl.h>
8: static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy)
9: {
10: PetscBool isPlex;
14: PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
15: if (isPlex) {
16: *plex = dm;
17: PetscObjectReference((PetscObject) dm);
18: } else {
19: PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
20: if (!*plex) {
21: DMConvert(dm,DMPLEX,plex);
22: PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
23: if (copy) {
24: const char *comps[3] = {"A", "dmAux"};
25: PetscObject obj;
26: PetscInt i;
28: {
29: /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
30: DMSubDomainHookLink link;
31: for (link = dm->subdomainhook; link; link = link->next) {
32: if (link->ddhook) {(*link->ddhook)(dm, *plex, link->ctx);}
33: }
34: }
35: for (i = 0; i < 3; i++) {
36: PetscObjectQuery((PetscObject) dm, comps[i], &obj);
37: PetscObjectCompose((PetscObject) *plex, comps[i], obj);
38: }
39: }
40: } else {
41: PetscObjectReference((PetscObject) *plex);
42: }
43: }
44: return(0);
45: }
47: static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom (void *ctx)
48: {
49: PetscFEGeom *geom = (PetscFEGeom *) ctx;
53: PetscFEGeomDestroy(&geom);
54: return(0);
55: }
57: static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
58: {
59: char composeStr[33] = {0};
60: PetscObjectId id;
61: PetscContainer container;
62: PetscErrorCode ierr;
65: PetscObjectGetId((PetscObject)quad,&id);
66: PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%x\n", id);
67: PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
68: if (container) {
69: PetscContainerGetPointer(container, (void **) geom);
70: } else {
71: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
72: PetscContainerCreate(PETSC_COMM_SELF,&container);
73: PetscContainerSetPointer(container, (void *) *geom);
74: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
75: PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
76: PetscContainerDestroy(&container);
77: }
78: return(0);
79: }
81: static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
82: {
84: *geom = NULL;
85: return(0);
86: }
88: /*@
89: DMPlexGetScale - Get the scale for the specified fundamental unit
91: Not collective
93: Input Arguments:
94: + dm - the DM
95: - unit - The SI unit
97: Output Argument:
98: . scale - The value used to scale all quantities with this unit
100: Level: advanced
102: .seealso: DMPlexSetScale(), PetscUnit
103: @*/
104: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
105: {
106: DM_Plex *mesh = (DM_Plex*) dm->data;
111: *scale = mesh->scale[unit];
112: return(0);
113: }
115: /*@
116: DMPlexSetScale - Set the scale for the specified fundamental unit
118: Not collective
120: Input Arguments:
121: + dm - the DM
122: . unit - The SI unit
123: - scale - The value used to scale all quantities with this unit
125: Level: advanced
127: .seealso: DMPlexGetScale(), PetscUnit
128: @*/
129: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
130: {
131: DM_Plex *mesh = (DM_Plex*) dm->data;
135: mesh->scale[unit] = scale;
136: return(0);
137: }
139: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
140: {
141: const PetscInt eps[3][3][3] = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}};
142: PetscInt *ctxInt = (PetscInt *) ctx;
143: PetscInt dim2 = ctxInt[0];
144: PetscInt d = ctxInt[1];
145: PetscInt i, j, k = dim > 2 ? d - dim : d;
148: if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %D does not match context dimension %D", dim, dim2);
149: for (i = 0; i < dim; i++) mode[i] = 0.;
150: if (d < dim) {
151: mode[d] = 1.; /* Translation along axis d */
152: } else {
153: for (i = 0; i < dim; i++) {
154: for (j = 0; j < dim; j++) {
155: mode[j] += eps[i][j][k]*X[i]; /* Rotation about axis d */
156: }
157: }
158: }
159: return(0);
160: }
162: /*@
163: DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
165: Collective on dm
167: Input Arguments:
168: + dm - the DM
169: - field - The field number for the rigid body space, or 0 for the default
171: Output Argument:
172: . sp - the null space
174: Note: This is necessary to provide a suitable coarse space for algebraic multigrid
176: Level: advanced
178: .seealso: MatNullSpaceCreate(), PCGAMG
179: @*/
180: PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
181: {
182: PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
183: MPI_Comm comm;
184: Vec mode[6];
185: PetscSection section, globalSection;
186: PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j;
187: PetscErrorCode ierr;
190: PetscObjectGetComm((PetscObject) dm, &comm);
191: DMGetDimension(dm, &dim);
192: DMGetCoordinateDim(dm, &dimEmbed);
193: DMGetNumFields(dm, &Nf);
194: if (Nf && (field < 0 || field >= Nf)) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, Nf)", field, Nf);
195: if (dim == 1 && Nf < 2) {
196: MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
197: return(0);
198: }
199: DMGetLocalSection(dm, §ion);
200: DMGetGlobalSection(dm, &globalSection);
201: PetscSectionGetConstrainedStorageSize(globalSection, &n);
202: PetscCalloc1(Nf, &func);
203: m = (dim*(dim+1))/2;
204: VecCreate(comm, &mode[0]);
205: VecSetSizes(mode[0], n, PETSC_DETERMINE);
206: VecSetUp(mode[0]);
207: VecGetSize(mode[0], &n);
208: mmin = PetscMin(m, n);
209: func[field] = DMPlexProjectRigidBody_Private;
210: for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
211: for (d = 0; d < m; d++) {
212: PetscInt ctx[2];
213: void *voidctx = (void *) (&ctx[0]);
215: ctx[0] = dimEmbed;
216: ctx[1] = d;
217: DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d]);
218: }
219: /* Orthonormalize system */
220: for (i = 0; i < mmin; ++i) {
221: PetscScalar dots[6];
223: VecNormalize(mode[i], NULL);
224: VecMDot(mode[i], mmin-i-1, mode+i+1, dots+i+1);
225: for (j = i+1; j < mmin; ++j) {
226: dots[j] *= -1.0;
227: VecAXPY(mode[j], dots[j], mode[i]);
228: }
229: }
230: MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);
231: for (i = 0; i < m; ++i) {VecDestroy(&mode[i]);}
232: PetscFree(func);
233: return(0);
234: }
236: /*@
237: DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
239: Collective on dm
241: Input Arguments:
242: + dm - the DM
243: . nb - The number of bodies
244: . label - The DMLabel marking each domain
245: . nids - The number of ids per body
246: - ids - An array of the label ids in sequence for each domain
248: Output Argument:
249: . sp - the null space
251: Note: This is necessary to provide a suitable coarse space for algebraic multigrid
253: Level: advanced
255: .seealso: MatNullSpaceCreate()
256: @*/
257: PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
258: {
259: MPI_Comm comm;
260: PetscSection section, globalSection;
261: Vec *mode;
262: PetscScalar *dots;
263: PetscInt dim, dimEmbed, n, m, b, d, i, j, off;
267: PetscObjectGetComm((PetscObject)dm,&comm);
268: DMGetDimension(dm, &dim);
269: DMGetCoordinateDim(dm, &dimEmbed);
270: DMGetLocalSection(dm, §ion);
271: DMGetGlobalSection(dm, &globalSection);
272: PetscSectionGetConstrainedStorageSize(globalSection, &n);
273: m = nb * (dim*(dim+1))/2;
274: PetscMalloc2(m, &mode, m, &dots);
275: VecCreate(comm, &mode[0]);
276: VecSetSizes(mode[0], n, PETSC_DETERMINE);
277: VecSetUp(mode[0]);
278: for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
279: for (b = 0, off = 0; b < nb; ++b) {
280: for (d = 0; d < m/nb; ++d) {
281: PetscInt ctx[2];
282: PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
283: void *voidctx = (void *) (&ctx[0]);
285: ctx[0] = dimEmbed;
286: ctx[1] = d;
287: DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
288: off += nids[b];
289: }
290: }
291: /* Orthonormalize system */
292: for (i = 0; i < m; ++i) {
293: PetscScalar dots[6];
295: VecNormalize(mode[i], NULL);
296: VecMDot(mode[i], m-i-1, mode+i+1, dots+i+1);
297: for (j = i+1; j < m; ++j) {
298: dots[j] *= -1.0;
299: VecAXPY(mode[j], dots[j], mode[i]);
300: }
301: }
302: MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
303: for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
304: PetscFree2(mode, dots);
305: return(0);
306: }
308: /*@
309: DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
310: are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
311: evaluating the dual space basis of that point. A basis function is associated with the point in its
312: transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
313: projection height, which is set with this function. By default, the maximum projection height is zero, which means
314: that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior
315: basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.
317: Input Parameters:
318: + dm - the DMPlex object
319: - height - the maximum projection height >= 0
321: Level: advanced
323: .seealso: DMPlexGetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
324: @*/
325: PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
326: {
327: DM_Plex *plex = (DM_Plex *) dm->data;
331: plex->maxProjectionHeight = height;
332: return(0);
333: }
335: /*@
336: DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
337: DMPlexProjectXXXLocal() functions.
339: Input Parameters:
340: . dm - the DMPlex object
342: Output Parameters:
343: . height - the maximum projection height
345: Level: intermediate
347: .seealso: DMPlexSetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
348: @*/
349: PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
350: {
351: DM_Plex *plex = (DM_Plex *) dm->data;
355: *height = plex->maxProjectionHeight;
356: return(0);
357: }
359: typedef struct {
360: PetscReal alpha; /* The first Euler angle, and in 2D the only one */
361: PetscReal beta; /* The second Euler angle */
362: PetscReal gamma; /* The third Euler angle */
363: PetscInt dim; /* The dimension of R */
364: PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */
365: PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
366: } RotCtx;
368: /*
369: Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
370: 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:
371: $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
372: $ 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.
373: $ The XYZ system rotates a third time about the z axis by gamma.
374: */
375: static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
376: {
377: RotCtx *rc = (RotCtx *) ctx;
378: PetscInt dim = rc->dim;
379: PetscReal c1, s1, c2, s2, c3, s3;
383: PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT);
384: switch (dim) {
385: case 2:
386: c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha);
387: rc->R[0] = c1;rc->R[1] = s1;
388: rc->R[2] = -s1;rc->R[3] = c1;
389: PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
390: DMPlex_Transpose2D_Internal(rc->RT);break;
391: break;
392: case 3:
393: c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha);
394: c2 = PetscCosReal(rc->beta); s2 = PetscSinReal(rc->beta);
395: c3 = PetscCosReal(rc->gamma);s3 = PetscSinReal(rc->gamma);
396: rc->R[0] = c1*c3 - c2*s1*s3;rc->R[1] = c3*s1 + c1*c2*s3;rc->R[2] = s2*s3;
397: rc->R[3] = -c1*s3 - c2*c3*s1;rc->R[4] = c1*c2*c3 - s1*s3; rc->R[5] = c3*s2;
398: rc->R[6] = s1*s2; rc->R[7] = -c1*s2; rc->R[8] = c2;
399: PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
400: DMPlex_Transpose3D_Internal(rc->RT);break;
401: break;
402: default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
403: }
404: return(0);
405: }
407: static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
408: {
409: RotCtx *rc = (RotCtx *) ctx;
413: PetscFree2(rc->R, rc->RT);
414: PetscFree(rc);
415: return(0);
416: }
418: static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx)
419: {
420: RotCtx *rc = (RotCtx *) ctx;
424: if (l2g) {*A = rc->R;}
425: else {*A = rc->RT;}
426: return(0);
427: }
429: PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx)
430: {
434: #if defined(PETSC_USE_COMPLEX)
435: switch (dim) {
436: case 2:
437: {
438: PetscScalar yt[2], zt[2];
440: yt[0] = y[0]; yt[1] = y[1];
441: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
442: z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]);
443: }
444: break;
445: case 3:
446: {
447: PetscScalar yt[3], zt[3];
449: yt[0] = y[0]; yt[1] = y[1]; yt[2] = y[2];
450: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
451: z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]); z[2] = PetscRealPart(zt[2]);
452: }
453: break;
454: }
455: #else
456: DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx);
457: #endif
458: return(0);
459: }
461: PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
462: {
463: const PetscScalar *A;
464: PetscErrorCode ierr;
467: (*dm->transformGetMatrix)(dm, x, l2g, &A, ctx);
468: switch (dim) {
469: case 2: DMPlex_Mult2D_Internal(A, 1, y, z);break;
470: case 3: DMPlex_Mult3D_Internal(A, 1, y, z);break;
471: }
472: return(0);
473: }
475: static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
476: {
477: PetscSection ts;
478: const PetscScalar *ta, *tva;
479: PetscInt dof;
480: PetscErrorCode ierr;
483: DMGetLocalSection(tdm, &ts);
484: PetscSectionGetFieldDof(ts, p, f, &dof);
485: VecGetArrayRead(tv, &ta);
486: DMPlexPointLocalFieldRead(tdm, p, f, ta, (void *) &tva);
487: if (l2g) {
488: switch (dof) {
489: case 4: DMPlex_Mult2D_Internal(tva, 1, a, a);break;
490: case 9: DMPlex_Mult3D_Internal(tva, 1, a, a);break;
491: }
492: } else {
493: switch (dof) {
494: case 4: DMPlex_MultTranspose2D_Internal(tva, 1, a, a);break;
495: case 9: DMPlex_MultTranspose3D_Internal(tva, 1, a, a);break;
496: }
497: }
498: VecRestoreArrayRead(tv, &ta);
499: return(0);
500: }
502: static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a)
503: {
504: PetscSection s, ts;
505: const PetscScalar *ta, *tvaf, *tvag;
506: PetscInt fdof, gdof, fpdof, gpdof;
507: PetscErrorCode ierr;
510: DMGetLocalSection(dm, &s);
511: DMGetLocalSection(tdm, &ts);
512: PetscSectionGetFieldDof(s, pf, f, &fpdof);
513: PetscSectionGetFieldDof(s, pg, g, &gpdof);
514: PetscSectionGetFieldDof(ts, pf, f, &fdof);
515: PetscSectionGetFieldDof(ts, pg, g, &gdof);
516: VecGetArrayRead(tv, &ta);
517: DMPlexPointLocalFieldRead(tdm, pf, f, ta, (void *) &tvaf);
518: DMPlexPointLocalFieldRead(tdm, pg, g, ta, (void *) &tvag);
519: if (l2g) {
520: switch (fdof) {
521: case 4: DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);break;
522: case 9: DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);break;
523: }
524: switch (gdof) {
525: case 4: DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);break;
526: case 9: DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);break;
527: }
528: } else {
529: switch (fdof) {
530: case 4: DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);break;
531: case 9: DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);break;
532: }
533: switch (gdof) {
534: case 4: DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);break;
535: case 9: DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);break;
536: }
537: }
538: VecRestoreArrayRead(tv, &ta);
539: return(0);
540: }
542: PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
543: {
544: PetscSection s;
545: PetscSection clSection;
546: IS clPoints;
547: const PetscInt *clp;
548: PetscInt *points = NULL;
549: PetscInt Nf, f, Np, cp, dof, d = 0;
550: PetscErrorCode ierr;
553: DMGetLocalSection(dm, &s);
554: PetscSectionGetNumFields(s, &Nf);
555: DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
556: for (f = 0; f < Nf; ++f) {
557: for (cp = 0; cp < Np*2; cp += 2) {
558: PetscSectionGetFieldDof(s, points[cp], f, &dof);
559: if (!dof) continue;
560: if (fieldActive[f]) {DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]);}
561: d += dof;
562: }
563: }
564: DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
565: return(0);
566: }
568: PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
569: {
570: PetscSection s;
571: PetscSection clSection;
572: IS clPoints;
573: const PetscInt *clp;
574: PetscInt *points = NULL;
575: PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
576: PetscErrorCode ierr;
579: DMGetLocalSection(dm, &s);
580: PetscSectionGetNumFields(s, &Nf);
581: DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
582: for (f = 0, r = 0; f < Nf; ++f) {
583: for (cpf = 0; cpf < Np*2; cpf += 2) {
584: PetscSectionGetFieldDof(s, points[cpf], f, &fdof);
585: for (g = 0, c = 0; g < Nf; ++g) {
586: for (cpg = 0; cpg < Np*2; cpg += 2) {
587: PetscSectionGetFieldDof(s, points[cpg], g, &gdof);
588: DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r*lda+c]);
589: c += gdof;
590: }
591: }
592: if (c != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %D should be %D", c, lda);
593: r += fdof;
594: }
595: }
596: if (r != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %D should be %D", c, lda);
597: DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
598: return(0);
599: }
601: static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
602: {
603: DM tdm;
604: Vec tv;
605: PetscSection ts, s;
606: const PetscScalar *ta;
607: PetscScalar *a, *va;
608: PetscInt pStart, pEnd, p, Nf, f;
609: PetscErrorCode ierr;
612: DMGetBasisTransformDM_Internal(dm, &tdm);
613: DMGetBasisTransformVec_Internal(dm, &tv);
614: DMGetLocalSection(tdm, &ts);
615: DMGetLocalSection(dm, &s);
616: PetscSectionGetChart(s, &pStart, &pEnd);
617: PetscSectionGetNumFields(s, &Nf);
618: VecGetArray(lv, &a);
619: VecGetArrayRead(tv, &ta);
620: for (p = pStart; p < pEnd; ++p) {
621: for (f = 0; f < Nf; ++f) {
622: DMPlexPointLocalFieldRef(dm, p, f, a, (void *) &va);
623: DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va);
624: }
625: }
626: VecRestoreArray(lv, &a);
627: VecRestoreArrayRead(tv, &ta);
628: return(0);
629: }
631: /*@
632: DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis
634: Input Parameters:
635: + dm - The DM
636: - lv - A local vector with values in the global basis
638: Output Parameters:
639: . lv - A local vector with values in the local basis
641: 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.
643: Level: developer
645: .seealso: DMPlexLocalToGlobalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
646: @*/
647: PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
648: {
654: DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE);
655: return(0);
656: }
658: /*@
659: DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis
661: Input Parameters:
662: + dm - The DM
663: - lv - A local vector with values in the local basis
665: Output Parameters:
666: . lv - A local vector with values in the global basis
668: 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.
670: Level: developer
672: .seealso: DMPlexGlobalToLocalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
673: @*/
674: PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
675: {
681: DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE);
682: return(0);
683: }
685: /*@
686: DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
687: and global solutions, to a local basis, appropriate for discretization integrals and assembly.
689: Input Parameters:
690: + dm - The DM
691: . alpha - The first Euler angle, and in 2D the only one
692: . beta - The second Euler angle
693: - gamma - The third Euler angle
695: Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
696: 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:
697: $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
698: $ 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.
699: $ The XYZ system rotates a third time about the z axis by gamma.
701: Level: developer
703: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()
704: @*/
705: PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
706: {
707: RotCtx *rc;
708: PetscInt cdim;
711: DMGetCoordinateDim(dm, &cdim);
712: PetscMalloc1(1, &rc);
713: dm->transformCtx = rc;
714: dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal;
715: dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal;
716: dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
717: rc->dim = cdim;
718: rc->alpha = alpha;
719: rc->beta = beta;
720: rc->gamma = gamma;
721: (*dm->transformSetUp)(dm, dm->transformCtx);
722: DMConstructBasisTransform_Internal(dm);
723: return(0);
724: }
726: /*@C
727: DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates
729: Input Parameters:
730: + dm - The DM, with a PetscDS that matches the problem being constrained
731: . time - The time
732: . field - The field to constrain
733: . Nc - The number of constrained field components, or 0 for all components
734: . comps - An array of constrained component numbers, or NULL for all components
735: . label - The DMLabel defining constrained points
736: . numids - The number of DMLabel ids for constrained points
737: . ids - An array of ids for constrained points
738: . func - A pointwise function giving boundary values
739: - ctx - An optional user context for bcFunc
741: Output Parameter:
742: . locX - A local vector to receives the boundary values
744: Level: developer
746: .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
747: @*/
748: 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)
749: {
750: PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
751: void **ctxs;
752: PetscInt numFields;
753: PetscErrorCode ierr;
756: DMGetNumFields(dm, &numFields);
757: PetscCalloc2(numFields,&funcs,numFields,&ctxs);
758: funcs[field] = func;
759: ctxs[field] = ctx;
760: DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
761: PetscFree2(funcs,ctxs);
762: return(0);
763: }
765: /*@C
766: DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data
768: Input Parameters:
769: + dm - The DM, with a PetscDS that matches the problem being constrained
770: . time - The time
771: . locU - A local vector with the input solution values
772: . field - The field to constrain
773: . Nc - The number of constrained field components, or 0 for all components
774: . comps - An array of constrained component numbers, or NULL for all components
775: . label - The DMLabel defining constrained points
776: . numids - The number of DMLabel ids for constrained points
777: . ids - An array of ids for constrained points
778: . func - A pointwise function giving boundary values
779: - ctx - An optional user context for bcFunc
781: Output Parameter:
782: . locX - A local vector to receives the boundary values
784: Level: developer
786: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
787: @*/
788: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
789: void (*func)(PetscInt, PetscInt, PetscInt,
790: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
791: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
792: PetscReal, const PetscReal[], PetscInt, const PetscScalar[],
793: PetscScalar[]),
794: void *ctx, Vec locX)
795: {
796: void (**funcs)(PetscInt, PetscInt, PetscInt,
797: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
798: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
799: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
800: void **ctxs;
801: PetscInt numFields;
802: PetscErrorCode ierr;
805: DMGetNumFields(dm, &numFields);
806: PetscCalloc2(numFields,&funcs,numFields,&ctxs);
807: funcs[field] = func;
808: ctxs[field] = ctx;
809: DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
810: PetscFree2(funcs,ctxs);
811: return(0);
812: }
814: /*@C
815: DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coodinates and boundary field data
817: Collective on dm
819: Input Parameters:
820: + dm - The DM, with a PetscDS that matches the problem being constrained
821: . time - The time
822: . locU - A local vector with the input solution values
823: . field - The field to constrain
824: . Nc - The number of constrained field components, or 0 for all components
825: . comps - An array of constrained component numbers, or NULL for all components
826: . label - The DMLabel defining constrained points
827: . numids - The number of DMLabel ids for constrained points
828: . ids - An array of ids for constrained points
829: . func - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal()
830: - ctx - An optional user context for bcFunc
832: Output Parameter:
833: . locX - A local vector to receive the boundary values
835: Level: developer
837: .seealso: DMProjectBdFieldLabelLocal(), DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
838: @*/
839: PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
840: void (*func)(PetscInt, PetscInt, PetscInt,
841: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
842: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
843: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[],
844: PetscScalar[]),
845: void *ctx, Vec locX)
846: {
847: void (**funcs)(PetscInt, PetscInt, PetscInt,
848: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
849: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
850: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
851: void **ctxs;
852: PetscInt numFields;
853: PetscErrorCode ierr;
856: DMGetNumFields(dm, &numFields);
857: PetscCalloc2(numFields,&funcs,numFields,&ctxs);
858: funcs[field] = func;
859: ctxs[field] = ctx;
860: DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
861: PetscFree2(funcs,ctxs);
862: return(0);
863: }
865: /*@C
866: DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
868: Input Parameters:
869: + dm - The DM, with a PetscDS that matches the problem being constrained
870: . time - The time
871: . faceGeometry - A vector with the FVM face geometry information
872: . cellGeometry - A vector with the FVM cell geometry information
873: . Grad - A vector with the FVM cell gradient information
874: . field - The field to constrain
875: . Nc - The number of constrained field components, or 0 for all components
876: . comps - An array of constrained component numbers, or NULL for all components
877: . label - The DMLabel defining constrained points
878: . numids - The number of DMLabel ids for constrained points
879: . ids - An array of ids for constrained points
880: . func - A pointwise function giving boundary values
881: - ctx - An optional user context for bcFunc
883: Output Parameter:
884: . locX - A local vector to receives the boundary values
886: Note: This implementation currently ignores the numcomps/comps argument from DMAddBoundary()
888: Level: developer
890: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
891: @*/
892: 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[],
893: PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
894: {
895: PetscDS prob;
896: PetscSF sf;
897: DM dmFace, dmCell, dmGrad;
898: const PetscScalar *facegeom, *cellgeom = NULL, *grad;
899: const PetscInt *leaves;
900: PetscScalar *x, *fx;
901: PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i;
902: PetscErrorCode ierr, ierru = 0;
905: DMGetPointSF(dm, &sf);
906: PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
907: nleaves = PetscMax(0, nleaves);
908: DMGetDimension(dm, &dim);
909: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
910: DMGetDS(dm, &prob);
911: VecGetDM(faceGeometry, &dmFace);
912: VecGetArrayRead(faceGeometry, &facegeom);
913: if (cellGeometry) {
914: VecGetDM(cellGeometry, &dmCell);
915: VecGetArrayRead(cellGeometry, &cellgeom);
916: }
917: if (Grad) {
918: PetscFV fv;
920: PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);
921: VecGetDM(Grad, &dmGrad);
922: VecGetArrayRead(Grad, &grad);
923: PetscFVGetNumComponents(fv, &pdim);
924: DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
925: }
926: VecGetArray(locX, &x);
927: for (i = 0; i < numids; ++i) {
928: IS faceIS;
929: const PetscInt *faces;
930: PetscInt numFaces, f;
932: DMLabelGetStratumIS(label, ids[i], &faceIS);
933: if (!faceIS) continue; /* No points with that id on this process */
934: ISGetLocalSize(faceIS, &numFaces);
935: ISGetIndices(faceIS, &faces);
936: for (f = 0; f < numFaces; ++f) {
937: const PetscInt face = faces[f], *cells;
938: PetscFVFaceGeom *fg;
940: if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
941: PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);
942: if (loc >= 0) continue;
943: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
944: DMPlexGetSupport(dm, face, &cells);
945: if (Grad) {
946: PetscFVCellGeom *cg;
947: PetscScalar *cx, *cgrad;
948: PetscScalar *xG;
949: PetscReal dx[3];
950: PetscInt d;
952: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);
953: DMPlexPointLocalRead(dm, cells[0], x, &cx);
954: DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);
955: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
956: DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
957: for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
958: ierru = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);
959: if (ierru) {
960: ISRestoreIndices(faceIS, &faces);
961: ISDestroy(&faceIS);
962: goto cleanup;
963: }
964: } else {
965: PetscScalar *xI;
966: PetscScalar *xG;
968: DMPlexPointLocalRead(dm, cells[0], x, &xI);
969: DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
970: ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
971: if (ierru) {
972: ISRestoreIndices(faceIS, &faces);
973: ISDestroy(&faceIS);
974: goto cleanup;
975: }
976: }
977: }
978: ISRestoreIndices(faceIS, &faces);
979: ISDestroy(&faceIS);
980: }
981: cleanup:
982: VecRestoreArray(locX, &x);
983: if (Grad) {
984: DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);
985: VecRestoreArrayRead(Grad, &grad);
986: }
987: if (cellGeometry) {VecRestoreArrayRead(cellGeometry, &cellgeom);}
988: VecRestoreArrayRead(faceGeometry, &facegeom);
989: CHKERRQ(ierru);
990: return(0);
991: }
993: static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
994: {
995: PetscInt c;
996: for (c = 0; c < Nc; ++c) u[c] = 0.0;
997: return 0;
998: }
1000: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1001: {
1002: PetscObject isZero;
1003: PetscDS prob;
1004: PetscInt numBd, b;
1008: DMGetDS(dm, &prob);
1009: PetscDSGetNumBoundary(prob, &numBd);
1010: PetscObjectQuery((PetscObject) locX, "__Vec_bc_zero__", &isZero);
1011: for (b = 0; b < numBd; ++b) {
1012: DMBoundaryConditionType type;
1013: const char *name, *labelname;
1014: DMLabel label;
1015: PetscInt field, Nc;
1016: const PetscInt *comps;
1017: PetscObject obj;
1018: PetscClassId id;
1019: void (*func)(void);
1020: PetscInt numids;
1021: const PetscInt *ids;
1022: void *ctx;
1024: DMGetBoundary(dm, b, &type, &name, &labelname, &field, &Nc, &comps, &func, NULL, &numids, &ids, &ctx);
1025: if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1026: DMGetLabel(dm, labelname, &label);
1027: if (!label) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "Label %s for boundary condition %s does not exist in the DM", labelname, name);
1028: DMGetField(dm, field, NULL, &obj);
1029: PetscObjectGetClassId(obj, &id);
1030: if (id == PETSCFE_CLASSID) {
1031: switch (type) {
1032: /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1033: case DM_BC_ESSENTIAL:
1034: if (isZero) func = (void (*)(void)) zero;
1035: DMPlexLabelAddCells(dm,label);
1036: DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);
1037: DMPlexLabelClearCells(dm,label);
1038: break;
1039: case DM_BC_ESSENTIAL_FIELD:
1040: DMPlexLabelAddCells(dm,label);
1041: DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
1042: (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1043: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1044: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func, ctx, locX);
1045: DMPlexLabelClearCells(dm,label);
1046: break;
1047: default: break;
1048: }
1049: } else if (id == PETSCFV_CLASSID) {
1050: if (!faceGeomFVM) continue;
1051: DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids,
1052: (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);
1053: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1054: }
1055: return(0);
1056: }
1058: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1059: {
1060: PetscObject isZero;
1061: PetscDS prob;
1062: PetscInt numBd, b;
1066: if (!locX) return(0);
1067: DMGetDS(dm, &prob);
1068: PetscDSGetNumBoundary(prob, &numBd);
1069: PetscObjectQuery((PetscObject) locX, "__Vec_bc_zero__", &isZero);
1070: for (b = 0; b < numBd; ++b) {
1071: DMBoundaryConditionType type;
1072: const char *name, *labelname;
1073: DMLabel label;
1074: PetscInt field, Nc;
1075: const PetscInt *comps;
1076: PetscObject obj;
1077: PetscClassId id;
1078: void (*func_t)(void);
1079: PetscInt numids;
1080: const PetscInt *ids;
1081: void *ctx;
1083: DMGetBoundary(dm, b, &type, &name, &labelname, &field, &Nc, &comps, NULL, &func_t, &numids, &ids, &ctx);
1084: if (!func_t) continue;
1085: if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1086: DMGetLabel(dm, labelname, &label);
1087: if (!label) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "Label %s for boundary condition %s does not exist in the DM", labelname, name);
1088: DMGetField(dm, field, NULL, &obj);
1089: PetscObjectGetClassId(obj, &id);
1090: if (id == PETSCFE_CLASSID) {
1091: switch (type) {
1092: /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1093: case DM_BC_ESSENTIAL:
1094: if (isZero) func_t = (void (*)(void)) zero;
1095: DMPlexLabelAddCells(dm,label);
1096: DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func_t, ctx, locX);
1097: DMPlexLabelClearCells(dm,label);
1098: break;
1099: case DM_BC_ESSENTIAL_FIELD:
1100: DMPlexLabelAddCells(dm,label);
1101: DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
1102: (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1103: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1104: PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func_t, ctx, locX);
1105: DMPlexLabelClearCells(dm,label);
1106: break;
1107: default: break;
1108: }
1109: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1110: }
1111: return(0);
1112: }
1114: /*@
1115: DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
1117: Input Parameters:
1118: + dm - The DM
1119: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1120: . time - The time
1121: . faceGeomFVM - Face geometry data for FV discretizations
1122: . cellGeomFVM - Cell geometry data for FV discretizations
1123: - gradFVM - Gradient reconstruction data for FV discretizations
1125: Output Parameters:
1126: . locX - Solution updated with boundary values
1128: Level: developer
1130: .seealso: DMProjectFunctionLabelLocal()
1131: @*/
1132: PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1133: {
1142: PetscTryMethod(dm,"DMPlexInsertBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX,time,faceGeomFVM,cellGeomFVM,gradFVM));
1143: return(0);
1144: }
1146: /*@
1147: DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derviative into the local solution vector
1149: Input Parameters:
1150: + dm - The DM
1151: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1152: . time - The time
1153: . faceGeomFVM - Face geometry data for FV discretizations
1154: . cellGeomFVM - Cell geometry data for FV discretizations
1155: - gradFVM - Gradient reconstruction data for FV discretizations
1157: Output Parameters:
1158: . locX_t - Solution updated with boundary values
1160: Level: developer
1162: .seealso: DMProjectFunctionLabelLocal()
1163: @*/
1164: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1165: {
1174: PetscTryMethod(dm,"DMPlexInsertTimeDerviativeBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX_t,time,faceGeomFVM,cellGeomFVM,gradFVM));
1175: return(0);
1176: }
1178: PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1179: {
1180: Vec localX;
1181: PetscErrorCode ierr;
1184: DMGetLocalVector(dm, &localX);
1185: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);
1186: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1187: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1188: DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);
1189: DMRestoreLocalVector(dm, &localX);
1190: return(0);
1191: }
1193: /*@C
1194: DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
1196: Collective on dm
1198: Input Parameters:
1199: + dm - The DM
1200: . time - The time
1201: . funcs - The functions to evaluate for each field component
1202: . ctxs - Optional array of contexts to pass to each function, or NULL.
1203: - localX - The coefficient vector u_h, a local vector
1205: Output Parameter:
1206: . diff - The diff ||u - u_h||_2
1208: Level: developer
1210: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
1211: @*/
1212: PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1213: {
1214: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
1215: DM tdm;
1216: Vec tv;
1217: PetscSection section;
1218: PetscQuadrature quad;
1219: PetscFEGeom fegeom;
1220: PetscScalar *funcVal, *interpolant;
1221: PetscReal *coords, *gcoords;
1222: PetscReal localDiff = 0.0;
1223: const PetscReal *quadWeights;
1224: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1225: PetscBool transform;
1226: PetscErrorCode ierr;
1229: DMGetDimension(dm, &dim);
1230: DMGetCoordinateDim(dm, &coordDim);
1231: fegeom.dimEmbed = coordDim;
1232: DMGetLocalSection(dm, §ion);
1233: PetscSectionGetNumFields(section, &numFields);
1234: DMGetBasisTransformDM_Internal(dm, &tdm);
1235: DMGetBasisTransformVec_Internal(dm, &tv);
1236: DMHasBasisTransform(dm, &transform);
1237: for (field = 0; field < numFields; ++field) {
1238: PetscObject obj;
1239: PetscClassId id;
1240: PetscInt Nc;
1242: DMGetField(dm, field, NULL, &obj);
1243: PetscObjectGetClassId(obj, &id);
1244: if (id == PETSCFE_CLASSID) {
1245: PetscFE fe = (PetscFE) obj;
1247: PetscFEGetQuadrature(fe, &quad);
1248: PetscFEGetNumComponents(fe, &Nc);
1249: } else if (id == PETSCFV_CLASSID) {
1250: PetscFV fv = (PetscFV) obj;
1252: PetscFVGetQuadrature(fv, &quad);
1253: PetscFVGetNumComponents(fv, &Nc);
1254: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1255: numComponents += Nc;
1256: }
1257: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1258: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1259: PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1260: DMPlexGetVTKCellHeight(dm, &cellHeight);
1261: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
1262: for (c = cStart; c < cEnd; ++c) {
1263: PetscScalar *x = NULL;
1264: PetscReal elemDiff = 0.0;
1265: PetscInt qc = 0;
1267: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1268: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1270: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1271: PetscObject obj;
1272: PetscClassId id;
1273: void * const ctx = ctxs ? ctxs[field] : NULL;
1274: PetscInt Nb, Nc, q, fc;
1276: DMGetField(dm, field, NULL, &obj);
1277: PetscObjectGetClassId(obj, &id);
1278: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1279: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1280: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1281: if (debug) {
1282: char title[1024];
1283: PetscSNPrintf(title, 1023, "Solution for Field %D", field);
1284: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1285: }
1286: for (q = 0; q < Nq; ++q) {
1287: PetscFEGeom qgeom;
1289: qgeom.dimEmbed = fegeom.dimEmbed;
1290: qgeom.J = &fegeom.J[q*coordDim*coordDim];
1291: qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim];
1292: qgeom.detJ = &fegeom.detJ[q];
1293: if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, point %D", (double)fegeom.detJ[q], c, q);
1294: if (transform) {
1295: gcoords = &coords[coordDim*Nq];
1296: DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);
1297: } else {
1298: gcoords = &coords[coordDim*q];
1299: }
1300: (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1301: if (ierr) {
1302: PetscErrorCode ierr2;
1303: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1304: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1305: ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1306:
1307: }
1308: if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1309: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1310: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1311: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1312: for (fc = 0; fc < Nc; ++fc) {
1313: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1314: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %D field %D,%D point %g %g %g diff %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.), (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1315: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1316: }
1317: }
1318: fieldOffset += Nb;
1319: qc += Nc;
1320: }
1321: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1322: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %D diff %g\n", c, (double)elemDiff);}
1323: localDiff += elemDiff;
1324: }
1325: PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1326: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1327: *diff = PetscSqrtReal(*diff);
1328: return(0);
1329: }
1331: 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)
1332: {
1333: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
1334: DM tdm;
1335: PetscSection section;
1336: PetscQuadrature quad;
1337: Vec localX, tv;
1338: PetscScalar *funcVal, *interpolant;
1339: const PetscReal *quadWeights;
1340: PetscFEGeom fegeom;
1341: PetscReal *coords, *gcoords;
1342: PetscReal localDiff = 0.0;
1343: PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1344: PetscBool transform;
1345: PetscErrorCode ierr;
1348: DMGetDimension(dm, &dim);
1349: DMGetCoordinateDim(dm, &coordDim);
1350: fegeom.dimEmbed = coordDim;
1351: DMGetLocalSection(dm, §ion);
1352: PetscSectionGetNumFields(section, &numFields);
1353: DMGetLocalVector(dm, &localX);
1354: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1355: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1356: DMGetBasisTransformDM_Internal(dm, &tdm);
1357: DMGetBasisTransformVec_Internal(dm, &tv);
1358: DMHasBasisTransform(dm, &transform);
1359: for (field = 0; field < numFields; ++field) {
1360: PetscFE fe;
1361: PetscInt Nc;
1363: DMGetField(dm, field, NULL, (PetscObject *) &fe);
1364: PetscFEGetQuadrature(fe, &quad);
1365: PetscFEGetNumComponents(fe, &Nc);
1366: numComponents += Nc;
1367: }
1368: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1369: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1370: /* DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
1371: PetscMalloc6(numComponents,&funcVal,coordDim*Nq,&coords,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ,numComponents*coordDim,&interpolant,Nq,&fegeom.detJ);
1372: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1373: for (c = cStart; c < cEnd; ++c) {
1374: PetscScalar *x = NULL;
1375: PetscReal elemDiff = 0.0;
1376: PetscInt qc = 0;
1378: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1379: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1381: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1382: PetscFE fe;
1383: void * const ctx = ctxs ? ctxs[field] : NULL;
1384: PetscInt Nb, Nc, q, fc;
1386: DMGetField(dm, field, NULL, (PetscObject *) &fe);
1387: PetscFEGetDimension(fe, &Nb);
1388: PetscFEGetNumComponents(fe, &Nc);
1389: if (debug) {
1390: char title[1024];
1391: PetscSNPrintf(title, 1023, "Solution for Field %D", field);
1392: DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1393: }
1394: for (q = 0; q < Nq; ++q) {
1395: PetscFEGeom qgeom;
1397: qgeom.dimEmbed = fegeom.dimEmbed;
1398: qgeom.J = &fegeom.J[q*coordDim*coordDim];
1399: qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim];
1400: qgeom.detJ = &fegeom.detJ[q];
1401: if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], c, q);
1402: if (transform) {
1403: gcoords = &coords[coordDim*Nq];
1404: DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);
1405: } else {
1406: gcoords = &coords[coordDim*q];
1407: }
1408: (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1409: if (ierr) {
1410: PetscErrorCode ierr2;
1411: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1412: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1413: ierr2 = PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);CHKERRQ(ierr2);
1414:
1415: }
1416: if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1417: PetscFEInterpolateGradient_Static(fe, &x[fieldOffset], &qgeom, q, interpolant);
1418: /* Overwrite with the dot product if the normal is given */
1419: if (n) {
1420: for (fc = 0; fc < Nc; ++fc) {
1421: PetscScalar sum = 0.0;
1422: PetscInt d;
1423: for (d = 0; d < dim; ++d) sum += interpolant[fc*dim+d]*n[d];
1424: interpolant[fc] = sum;
1425: }
1426: }
1427: for (fc = 0; fc < Nc; ++fc) {
1428: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1429: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %D fieldDer %D,%D diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1430: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1431: }
1432: }
1433: fieldOffset += Nb;
1434: qc += Nc;
1435: }
1436: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1437: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %D diff %g\n", c, (double)elemDiff);}
1438: localDiff += elemDiff;
1439: }
1440: PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);
1441: DMRestoreLocalVector(dm, &localX);
1442: MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1443: *diff = PetscSqrtReal(*diff);
1444: return(0);
1445: }
1447: PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1448: {
1449: const PetscInt debug = ((DM_Plex*)dm->data)->printL2;
1450: DM tdm;
1451: DMLabel depthLabel;
1452: PetscSection section;
1453: Vec localX, tv;
1454: PetscReal *localDiff;
1455: PetscInt dim, depth, dE, Nf, f, Nds, s;
1456: PetscBool transform;
1457: PetscErrorCode ierr;
1460: DMGetDimension(dm, &dim);
1461: DMGetCoordinateDim(dm, &dE);
1462: DMGetLocalSection(dm, §ion);
1463: DMGetLocalVector(dm, &localX);
1464: DMGetBasisTransformDM_Internal(dm, &tdm);
1465: DMGetBasisTransformVec_Internal(dm, &tv);
1466: DMHasBasisTransform(dm, &transform);
1467: DMGetNumFields(dm, &Nf);
1468: DMPlexGetDepthLabel(dm, &depthLabel);
1469: DMLabelGetNumValues(depthLabel, &depth);
1471: VecSet(localX, 0.0);
1472: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1473: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1474: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1475: DMGetNumDS(dm, &Nds);
1476: PetscCalloc1(Nf, &localDiff);
1477: for (s = 0; s < Nds; ++s) {
1478: PetscDS ds;
1479: DMLabel label;
1480: IS fieldIS, pointIS;
1481: const PetscInt *fields, *points = NULL;
1482: PetscQuadrature quad;
1483: const PetscReal *quadPoints, *quadWeights;
1484: PetscFEGeom fegeom;
1485: PetscReal *coords, *gcoords;
1486: PetscScalar *funcVal, *interpolant;
1487: PetscBool isHybrid;
1488: PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;
1490: DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
1491: ISGetIndices(fieldIS, &fields);
1492: PetscDSGetHybrid(ds, &isHybrid);
1493: PetscDSGetNumFields(ds, &dsNf);
1494: PetscDSGetTotalComponents(ds, &totNc);
1495: PetscDSGetQuadrature(ds, &quad);
1496: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1497: if ((qNc != 1) && (qNc != totNc)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, totNc);
1498: PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE*(Nq+1), &coords,Nq, &fegeom.detJ, dE*dE*Nq, &fegeom.J, dE*dE*Nq, &fegeom.invJ);
1499: if (!label) {
1500: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1501: } else {
1502: DMLabelGetStratumIS(label, 1, &pointIS);
1503: ISGetLocalSize(pointIS, &cEnd);
1504: ISGetIndices(pointIS, &points);
1505: }
1506: for (c = cStart; c < cEnd; ++c) {
1507: const PetscInt cell = points ? points[c] : c;
1508: PetscScalar *x = NULL;
1509: PetscInt qc = 0, fOff = 0, dep, fStart = isHybrid ? dsNf-1 : 0;
1511: DMLabelGetValue(depthLabel, cell, &dep);
1512: if (dep != depth-1) continue;
1513: if (isHybrid) {
1514: const PetscInt *cone;
1516: DMPlexGetCone(dm, cell, &cone);
1517: DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1518: } else {
1519: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1520: }
1521: DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x);
1522: for (f = fStart; f < dsNf; ++f) {
1523: PetscObject obj;
1524: PetscClassId id;
1525: void * const ctx = ctxs ? ctxs[fields[f]] : NULL;
1526: PetscInt Nb, Nc, q, fc;
1527: PetscReal elemDiff = 0.0;
1529: PetscDSGetDiscretization(ds, f, &obj);
1530: PetscObjectGetClassId(obj, &id);
1531: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1532: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1533: else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]);
1534: if (debug) {
1535: char title[1024];
1536: PetscSNPrintf(title, 1023, "Solution for Field %D", fields[f]);
1537: DMPrintCellVector(cell, title, Nb, &x[fOff]);
1538: }
1539: for (q = 0; q < Nq; ++q) {
1540: PetscFEGeom qgeom;
1542: qgeom.dimEmbed = fegeom.dimEmbed;
1543: qgeom.J = &fegeom.J[q*dE*dE];
1544: qgeom.invJ = &fegeom.invJ[q*dE*dE];
1545: qgeom.detJ = &fegeom.detJ[q];
1546: if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %D, quadrature point %D", (double)fegeom.detJ[q], cell, q);
1547: if (transform) {
1548: gcoords = &coords[dE*Nq];
1549: DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE*q], PETSC_TRUE, dE, &coords[dE*q], gcoords, dm->transformCtx);
1550: } else {
1551: gcoords = &coords[dE*q];
1552: }
1553: (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1554: if (ierr) {
1555: PetscErrorCode ierr2;
1556: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);CHKERRQ(ierr2);
1557: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1558: ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1559:
1560: }
1561: if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[dE*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1562: /* Call once for each face, except for lagrange field */
1563: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fOff], &qgeom, q, interpolant);}
1564: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fOff], q, interpolant);}
1565: else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]);
1566: for (fc = 0; fc < Nc; ++fc) {
1567: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1568: if (debug) {PetscPrintf(PETSC_COMM_SELF, " cell %D field %D,%D 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.), (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1569: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1570: }
1571: }
1572: fOff += Nb;
1573: qc += Nc;
1574: localDiff[fields[f]] += elemDiff;
1575: if (debug) {PetscPrintf(PETSC_COMM_SELF, " cell %D field %D cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]]);}
1576: }
1577: DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);
1578: }
1579: if (label) {
1580: ISRestoreIndices(pointIS, &points);
1581: ISDestroy(&pointIS);
1582: }
1583: ISRestoreIndices(fieldIS, &fields);
1584: PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1585: }
1586: DMRestoreLocalVector(dm, &localX);
1587: MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1588: PetscFree(localDiff);
1589: for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
1590: return(0);
1591: }
1593: /*@C
1594: 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.
1596: Collective on dm
1598: Input Parameters:
1599: + dm - The DM
1600: . time - The time
1601: . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
1602: . ctxs - Optional array of contexts to pass to each function, or NULL.
1603: - X - The coefficient vector u_h
1605: Output Parameter:
1606: . D - A Vec which holds the difference ||u - u_h||_2 for each cell
1608: Level: developer
1610: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1611: @*/
1612: PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1613: {
1614: PetscSection section;
1615: PetscQuadrature quad;
1616: Vec localX;
1617: PetscFEGeom fegeom;
1618: PetscScalar *funcVal, *interpolant;
1619: PetscReal *coords;
1620: const PetscReal *quadPoints, *quadWeights;
1621: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1622: PetscErrorCode ierr;
1625: VecSet(D, 0.0);
1626: DMGetDimension(dm, &dim);
1627: DMGetCoordinateDim(dm, &coordDim);
1628: DMGetLocalSection(dm, §ion);
1629: PetscSectionGetNumFields(section, &numFields);
1630: DMGetLocalVector(dm, &localX);
1631: DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1632: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1633: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1634: for (field = 0; field < numFields; ++field) {
1635: PetscObject obj;
1636: PetscClassId id;
1637: PetscInt Nc;
1639: DMGetField(dm, field, NULL, &obj);
1640: PetscObjectGetClassId(obj, &id);
1641: if (id == PETSCFE_CLASSID) {
1642: PetscFE fe = (PetscFE) obj;
1644: PetscFEGetQuadrature(fe, &quad);
1645: PetscFEGetNumComponents(fe, &Nc);
1646: } else if (id == PETSCFV_CLASSID) {
1647: PetscFV fv = (PetscFV) obj;
1649: PetscFVGetQuadrature(fv, &quad);
1650: PetscFVGetNumComponents(fv, &Nc);
1651: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1652: numComponents += Nc;
1653: }
1654: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1655: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1656: PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1657: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1658: for (c = cStart; c < cEnd; ++c) {
1659: PetscScalar *x = NULL;
1660: PetscScalar elemDiff = 0.0;
1661: PetscInt qc = 0;
1663: DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1664: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
1666: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1667: PetscObject obj;
1668: PetscClassId id;
1669: void * const ctx = ctxs ? ctxs[field] : NULL;
1670: PetscInt Nb, Nc, q, fc;
1672: DMGetField(dm, field, NULL, &obj);
1673: PetscObjectGetClassId(obj, &id);
1674: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1675: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1676: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1677: if (funcs[field]) {
1678: for (q = 0; q < Nq; ++q) {
1679: PetscFEGeom qgeom;
1681: qgeom.dimEmbed = fegeom.dimEmbed;
1682: qgeom.J = &fegeom.J[q*coordDim*coordDim];
1683: qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim];
1684: qgeom.detJ = &fegeom.detJ[q];
1685: if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], c, q);
1686: (*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx);
1687: if (ierr) {
1688: PetscErrorCode ierr2;
1689: ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1690: ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1691: ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1692:
1693: }
1694: if (id == PETSCFE_CLASSID) {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1695: else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1696: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1697: for (fc = 0; fc < Nc; ++fc) {
1698: const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1699: elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1700: }
1701: }
1702: }
1703: fieldOffset += Nb;
1704: qc += Nc;
1705: }
1706: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1707: VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);
1708: }
1709: PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1710: DMRestoreLocalVector(dm, &localX);
1711: VecSqrtAbs(D);
1712: return(0);
1713: }
1715: /*@C
1716: DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec.
1718: Collective on dm
1720: Input Parameters:
1721: + dm - The DM
1722: - LocX - The coefficient vector u_h
1724: Output Parameter:
1725: . locC - A Vec which holds the Clement interpolant of the gradient
1727: Notes:
1728: Add citation to (Clement, 1975) and definition of the interpolant
1729: \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
1731: Level: developer
1733: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1734: @*/
1735: PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1736: {
1737: DM_Plex *mesh = (DM_Plex *) dm->data;
1738: PetscInt debug = mesh->printFEM;
1739: DM dmC;
1740: PetscSection section;
1741: PetscQuadrature quad;
1742: PetscScalar *interpolant, *gradsum;
1743: PetscFEGeom fegeom;
1744: PetscReal *coords;
1745: const PetscReal *quadPoints, *quadWeights;
1746: PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
1747: PetscErrorCode ierr;
1750: VecGetDM(locC, &dmC);
1751: VecSet(locC, 0.0);
1752: DMGetDimension(dm, &dim);
1753: DMGetCoordinateDim(dm, &coordDim);
1754: fegeom.dimEmbed = coordDim;
1755: DMGetLocalSection(dm, §ion);
1756: PetscSectionGetNumFields(section, &numFields);
1757: for (field = 0; field < numFields; ++field) {
1758: PetscObject obj;
1759: PetscClassId id;
1760: PetscInt Nc;
1762: DMGetField(dm, field, NULL, &obj);
1763: PetscObjectGetClassId(obj, &id);
1764: if (id == PETSCFE_CLASSID) {
1765: PetscFE fe = (PetscFE) obj;
1767: PetscFEGetQuadrature(fe, &quad);
1768: PetscFEGetNumComponents(fe, &Nc);
1769: } else if (id == PETSCFV_CLASSID) {
1770: PetscFV fv = (PetscFV) obj;
1772: PetscFVGetQuadrature(fv, &quad);
1773: PetscFVGetNumComponents(fv, &Nc);
1774: } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1775: numComponents += Nc;
1776: }
1777: PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1778: if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1779: PetscMalloc6(coordDim*numComponents*2,&gradsum,coordDim*numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1780: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1781: DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1782: for (v = vStart; v < vEnd; ++v) {
1783: PetscScalar volsum = 0.0;
1784: PetscInt *star = NULL;
1785: PetscInt starSize, st, d, fc;
1787: PetscArrayzero(gradsum, coordDim*numComponents);
1788: DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1789: for (st = 0; st < starSize*2; st += 2) {
1790: const PetscInt cell = star[st];
1791: PetscScalar *grad = &gradsum[coordDim*numComponents];
1792: PetscScalar *x = NULL;
1793: PetscReal vol = 0.0;
1795: if ((cell < cStart) || (cell >= cEnd)) continue;
1796: DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1797: DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1798: for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1799: PetscObject obj;
1800: PetscClassId id;
1801: PetscInt Nb, Nc, q, qc = 0;
1803: PetscArrayzero(grad, coordDim*numComponents);
1804: DMGetField(dm, field, NULL, &obj);
1805: PetscObjectGetClassId(obj, &id);
1806: if (id == PETSCFE_CLASSID) {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1807: else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1808: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1809: for (q = 0; q < Nq; ++q) {
1810: PetscFEGeom qgeom;
1812: qgeom.dimEmbed = fegeom.dimEmbed;
1813: qgeom.J = &fegeom.J[q*coordDim*coordDim];
1814: qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim];
1815: qgeom.detJ = &fegeom.detJ[q];
1816: if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], cell, q);
1817: if (ierr) {
1818: PetscErrorCode ierr2;
1819: ierr2 = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr2);
1820: ierr2 = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr2);
1821: ierr2 = PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1822:
1823: }
1824: if (id == PETSCFE_CLASSID) {PetscFEInterpolateGradient_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1825: else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1826: for (fc = 0; fc < Nc; ++fc) {
1827: const PetscReal wt = quadWeights[q*qNc+qc+fc];
1829: for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*fegeom.detJ[q];
1830: }
1831: vol += quadWeights[q*qNc]*fegeom.detJ[q];
1832: }
1833: fieldOffset += Nb;
1834: qc += Nc;
1835: }
1836: DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1837: for (fc = 0; fc < numComponents; ++fc) {
1838: for (d = 0; d < coordDim; ++d) {
1839: gradsum[fc*coordDim+d] += grad[fc*coordDim+d];
1840: }
1841: }
1842: volsum += vol;
1843: if (debug) {
1844: PetscPrintf(PETSC_COMM_SELF, "Cell %D gradient: [", cell);
1845: for (fc = 0; fc < numComponents; ++fc) {
1846: for (d = 0; d < coordDim; ++d) {
1847: if (fc || d > 0) {PetscPrintf(PETSC_COMM_SELF, ", ");}
1848: PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]));
1849: }
1850: }
1851: PetscPrintf(PETSC_COMM_SELF, "]\n");
1852: }
1853: }
1854: for (fc = 0; fc < numComponents; ++fc) {
1855: for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum;
1856: }
1857: DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1858: DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);
1859: }
1860: PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1861: return(0);
1862: }
1864: static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
1865: {
1866: DM dmAux = NULL;
1867: PetscDS prob, probAux = NULL;
1868: PetscSection section, sectionAux;
1869: Vec locX, locA;
1870: PetscInt dim, numCells = cEnd - cStart, c, f;
1871: PetscBool useFVM = PETSC_FALSE;
1872: /* DS */
1873: PetscInt Nf, totDim, *uOff, *uOff_x, numConstants;
1874: PetscInt NfAux, totDimAux, *aOff;
1875: PetscScalar *u, *a;
1876: const PetscScalar *constants;
1877: /* Geometry */
1878: PetscFEGeom *cgeomFEM;
1879: DM dmGrad;
1880: PetscQuadrature affineQuad = NULL;
1881: Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
1882: PetscFVCellGeom *cgeomFVM;
1883: const PetscScalar *lgrad;
1884: PetscInt maxDegree;
1885: DMField coordField;
1886: IS cellIS;
1887: PetscErrorCode ierr;
1890: DMGetDS(dm, &prob);
1891: DMGetDimension(dm, &dim);
1892: DMGetLocalSection(dm, §ion);
1893: PetscSectionGetNumFields(section, &Nf);
1894: /* Determine which discretizations we have */
1895: for (f = 0; f < Nf; ++f) {
1896: PetscObject obj;
1897: PetscClassId id;
1899: PetscDSGetDiscretization(prob, f, &obj);
1900: PetscObjectGetClassId(obj, &id);
1901: if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
1902: }
1903: /* Get local solution with boundary values */
1904: DMGetLocalVector(dm, &locX);
1905: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1906: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1907: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1908: /* Read DS information */
1909: PetscDSGetTotalDimension(prob, &totDim);
1910: PetscDSGetComponentOffsets(prob, &uOff);
1911: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1912: ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS);
1913: PetscDSGetConstants(prob, &numConstants, &constants);
1914: /* Read Auxiliary DS information */
1915: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
1916: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1917: if (dmAux) {
1918: DMGetDS(dmAux, &probAux);
1919: PetscDSGetNumFields(probAux, &NfAux);
1920: DMGetLocalSection(dmAux, §ionAux);
1921: PetscDSGetTotalDimension(probAux, &totDimAux);
1922: PetscDSGetComponentOffsets(probAux, &aOff);
1923: }
1924: /* Allocate data arrays */
1925: PetscCalloc1(numCells*totDim, &u);
1926: if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
1927: /* Read out geometry */
1928: DMGetCoordinateField(dm,&coordField);
1929: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
1930: if (maxDegree <= 1) {
1931: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
1932: if (affineQuad) {
1933: DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM);
1934: }
1935: }
1936: if (useFVM) {
1937: PetscFV fv = NULL;
1938: Vec grad;
1939: PetscInt fStart, fEnd;
1940: PetscBool compGrad;
1942: for (f = 0; f < Nf; ++f) {
1943: PetscObject obj;
1944: PetscClassId id;
1946: PetscDSGetDiscretization(prob, f, &obj);
1947: PetscObjectGetClassId(obj, &id);
1948: if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;}
1949: }
1950: PetscFVGetComputeGradients(fv, &compGrad);
1951: PetscFVSetComputeGradients(fv, PETSC_TRUE);
1952: DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);
1953: DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);
1954: PetscFVSetComputeGradients(fv, compGrad);
1955: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1956: /* Reconstruct and limit cell gradients */
1957: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1958: DMGetGlobalVector(dmGrad, &grad);
1959: DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
1960: /* Communicate gradient values */
1961: DMGetLocalVector(dmGrad, &locGrad);
1962: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
1963: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
1964: DMRestoreGlobalVector(dmGrad, &grad);
1965: /* Handle non-essential (e.g. outflow) boundary values */
1966: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);
1967: VecGetArrayRead(locGrad, &lgrad);
1968: }
1969: /* Read out data from inputs */
1970: for (c = cStart; c < cEnd; ++c) {
1971: PetscScalar *x = NULL;
1972: PetscInt i;
1974: DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);
1975: for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1976: DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);
1977: if (dmAux) {
1978: DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);
1979: for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1980: DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);
1981: }
1982: }
1983: /* Do integration for each field */
1984: for (f = 0; f < Nf; ++f) {
1985: PetscObject obj;
1986: PetscClassId id;
1987: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
1989: PetscDSGetDiscretization(prob, f, &obj);
1990: PetscObjectGetClassId(obj, &id);
1991: if (id == PETSCFE_CLASSID) {
1992: PetscFE fe = (PetscFE) obj;
1993: PetscQuadrature q;
1994: PetscFEGeom *chunkGeom = NULL;
1995: PetscInt Nq, Nb;
1997: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1998: PetscFEGetQuadrature(fe, &q);
1999: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2000: PetscFEGetDimension(fe, &Nb);
2001: blockSize = Nb*Nq;
2002: batchSize = numBlocks * blockSize;
2003: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2004: numChunks = numCells / (numBatches*batchSize);
2005: Ne = numChunks*numBatches*batchSize;
2006: Nr = numCells % (numBatches*batchSize);
2007: offset = numCells - Nr;
2008: if (!affineQuad) {
2009: DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM);
2010: }
2011: PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
2012: PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral);
2013: PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom);
2014: PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf]);
2015: PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom);
2016: if (!affineQuad) {
2017: PetscFEGeomDestroy(&cgeomFEM);
2018: }
2019: } else if (id == PETSCFV_CLASSID) {
2020: PetscInt foff;
2021: PetscPointFunc obj_func;
2022: PetscScalar lint;
2024: PetscDSGetObjective(prob, f, &obj_func);
2025: PetscDSGetFieldOffset(prob, f, &foff);
2026: if (obj_func) {
2027: for (c = 0; c < numCells; ++c) {
2028: PetscScalar *u_x;
2030: DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);
2031: 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);
2032: cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume;
2033: }
2034: }
2035: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
2036: }
2037: /* Cleanup data arrays */
2038: if (useFVM) {
2039: VecRestoreArrayRead(locGrad, &lgrad);
2040: VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
2041: DMRestoreLocalVector(dmGrad, &locGrad);
2042: VecDestroy(&faceGeometryFVM);
2043: VecDestroy(&cellGeometryFVM);
2044: DMDestroy(&dmGrad);
2045: }
2046: if (dmAux) {PetscFree(a);}
2047: PetscFree(u);
2048: /* Cleanup */
2049: if (affineQuad) {
2050: PetscFEGeomDestroy(&cgeomFEM);
2051: }
2052: PetscQuadratureDestroy(&affineQuad);
2053: ISDestroy(&cellIS);
2054: DMRestoreLocalVector(dm, &locX);
2055: return(0);
2056: }
2058: /*@
2059: DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
2061: Input Parameters:
2062: + dm - The mesh
2063: . X - Global input vector
2064: - user - The user context
2066: Output Parameter:
2067: . integral - Integral for each field
2069: Level: developer
2071: .seealso: DMPlexComputeResidualFEM()
2072: @*/
2073: PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
2074: {
2075: DM_Plex *mesh = (DM_Plex *) dm->data;
2076: PetscScalar *cintegral, *lintegral;
2077: PetscInt Nf, f, cellHeight, cStart, cEnd, cell;
2084: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2085: DMGetNumFields(dm, &Nf);
2086: DMPlexGetVTKCellHeight(dm, &cellHeight);
2087: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2088: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2089: PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral);
2090: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2091: /* Sum up values */
2092: for (cell = cStart; cell < cEnd; ++cell) {
2093: const PetscInt c = cell - cStart;
2095: if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
2096: for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f];
2097: }
2098: MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm));
2099: if (mesh->printFEM) {
2100: PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:");
2101: for (f = 0; f < Nf; ++f) {PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]));}
2102: PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");
2103: }
2104: PetscFree2(lintegral, cintegral);
2105: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2106: return(0);
2107: }
2109: /*@
2110: DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
2112: Input Parameters:
2113: + dm - The mesh
2114: . X - Global input vector
2115: - user - The user context
2117: Output Parameter:
2118: . integral - Cellwise integrals for each field
2120: Level: developer
2122: .seealso: DMPlexComputeResidualFEM()
2123: @*/
2124: PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
2125: {
2126: DM_Plex *mesh = (DM_Plex *) dm->data;
2127: DM dmF;
2128: PetscSection sectionF;
2129: PetscScalar *cintegral, *af;
2130: PetscInt Nf, f, cellHeight, cStart, cEnd, cell;
2137: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2138: DMGetNumFields(dm, &Nf);
2139: DMPlexGetVTKCellHeight(dm, &cellHeight);
2140: DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2141: /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2142: PetscCalloc1((cEnd-cStart)*Nf, &cintegral);
2143: DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2144: /* Put values in F*/
2145: VecGetDM(F, &dmF);
2146: DMGetLocalSection(dmF, §ionF);
2147: VecGetArray(F, &af);
2148: for (cell = cStart; cell < cEnd; ++cell) {
2149: const PetscInt c = cell - cStart;
2150: PetscInt dof, off;
2152: if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
2153: PetscSectionGetDof(sectionF, cell, &dof);
2154: PetscSectionGetOffset(sectionF, cell, &off);
2155: if (dof != Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf);
2156: for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f];
2157: }
2158: VecRestoreArray(F, &af);
2159: PetscFree(cintegral);
2160: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2161: return(0);
2162: }
2164: static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS,
2165: void (*func)(PetscInt, PetscInt, PetscInt,
2166: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2167: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2168: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
2169: PetscScalar *fintegral, void *user)
2170: {
2171: DM plex = NULL, plexA = NULL;
2172: DMEnclosureType encAux;
2173: PetscDS prob, probAux = NULL;
2174: PetscSection section, sectionAux = NULL;
2175: Vec locA = NULL;
2176: DMField coordField;
2177: PetscInt Nf, totDim, *uOff, *uOff_x;
2178: PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL;
2179: PetscScalar *u, *a = NULL;
2180: const PetscScalar *constants;
2181: PetscInt numConstants, f;
2182: PetscErrorCode ierr;
2185: DMGetCoordinateField(dm, &coordField);
2186: DMConvert(dm, DMPLEX, &plex);
2187: DMGetDS(dm, &prob);
2188: DMGetLocalSection(dm, §ion);
2189: PetscSectionGetNumFields(section, &Nf);
2190: /* Determine which discretizations we have */
2191: for (f = 0; f < Nf; ++f) {
2192: PetscObject obj;
2193: PetscClassId id;
2195: PetscDSGetDiscretization(prob, f, &obj);
2196: PetscObjectGetClassId(obj, &id);
2197: if (id == PETSCFV_CLASSID) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f);
2198: }
2199: /* Read DS information */
2200: PetscDSGetTotalDimension(prob, &totDim);
2201: PetscDSGetComponentOffsets(prob, &uOff);
2202: PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
2203: PetscDSGetConstants(prob, &numConstants, &constants);
2204: /* Read Auxiliary DS information */
2205: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
2206: if (locA) {
2207: DM dmAux;
2209: VecGetDM(locA, &dmAux);
2210: DMGetEnclosureRelation(dmAux, dm, &encAux);
2211: DMConvert(dmAux, DMPLEX, &plexA);
2212: DMGetDS(dmAux, &probAux);
2213: PetscDSGetNumFields(probAux, &NfAux);
2214: DMGetLocalSection(dmAux, §ionAux);
2215: PetscDSGetTotalDimension(probAux, &totDimAux);
2216: PetscDSGetComponentOffsets(probAux, &aOff);
2217: }
2218: /* Integrate over points */
2219: {
2220: PetscFEGeom *fgeom, *chunkGeom = NULL;
2221: PetscInt maxDegree;
2222: PetscQuadrature qGeom = NULL;
2223: const PetscInt *points;
2224: PetscInt numFaces, face, Nq, field;
2225: PetscInt numChunks, chunkSize, chunk, Nr, offset;
2227: ISGetLocalSize(pointIS, &numFaces);
2228: ISGetIndices(pointIS, &points);
2229: PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a);
2230: DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
2231: for (field = 0; field < Nf; ++field) {
2232: PetscFE fe;
2234: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
2235: if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);}
2236: if (!qGeom) {
2237: PetscFEGetFaceQuadrature(fe, &qGeom);
2238: PetscObjectReference((PetscObject) qGeom);
2239: }
2240: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
2241: DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2242: for (face = 0; face < numFaces; ++face) {
2243: const PetscInt point = points[face], *support, *cone;
2244: PetscScalar *x = NULL;
2245: PetscInt i, coneSize, faceLoc;
2247: DMPlexGetSupport(dm, point, &support);
2248: DMPlexGetConeSize(dm, support[0], &coneSize);
2249: DMPlexGetCone(dm, support[0], &cone);
2250: for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
2251: if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]);
2252: fgeom->face[face][0] = faceLoc;
2253: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
2254: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
2255: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
2256: if (locA) {
2257: PetscInt subp;
2258: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
2259: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
2260: for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
2261: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
2262: }
2263: }
2264: /* Get blocking */
2265: {
2266: PetscQuadrature q;
2267: PetscInt numBatches, batchSize, numBlocks, blockSize;
2268: PetscInt Nq, Nb;
2270: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
2271: PetscFEGetQuadrature(fe, &q);
2272: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2273: PetscFEGetDimension(fe, &Nb);
2274: blockSize = Nb*Nq;
2275: batchSize = numBlocks * blockSize;
2276: chunkSize = numBatches*batchSize;
2277: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2278: numChunks = numFaces / chunkSize;
2279: Nr = numFaces % chunkSize;
2280: offset = numFaces - Nr;
2281: }
2282: /* Do integration for each field */
2283: for (chunk = 0; chunk < numChunks; ++chunk) {
2284: PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);
2285: PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
2286: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
2287: }
2288: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
2289: PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);
2290: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
2291: /* Cleanup data arrays */
2292: DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2293: PetscQuadratureDestroy(&qGeom);
2294: PetscFree2(u, a);
2295: ISRestoreIndices(pointIS, &points);
2296: }
2297: }
2298: if (plex) {DMDestroy(&plex);}
2299: if (plexA) {DMDestroy(&plexA);}
2300: return(0);
2301: }
2303: /*@
2304: DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
2306: Input Parameters:
2307: + dm - The mesh
2308: . X - Global input vector
2309: . label - The boundary DMLabel
2310: . numVals - The number of label values to use, or PETSC_DETERMINE for all values
2311: . vals - The label values to use, or PETSC_NULL for all values
2312: . func = The function to integrate along the boundary
2313: - user - The user context
2315: Output Parameter:
2316: . integral - Integral for each field
2318: Level: developer
2320: .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM()
2321: @*/
2322: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[],
2323: void (*func)(PetscInt, PetscInt, PetscInt,
2324: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2325: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2326: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
2327: PetscScalar *integral, void *user)
2328: {
2329: Vec locX;
2330: PetscSection section;
2331: DMLabel depthLabel;
2332: IS facetIS;
2333: PetscInt dim, Nf, f, v;
2342: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2343: DMPlexGetDepthLabel(dm, &depthLabel);
2344: DMGetDimension(dm, &dim);
2345: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
2346: DMGetLocalSection(dm, §ion);
2347: PetscSectionGetNumFields(section, &Nf);
2348: /* Get local solution with boundary values */
2349: DMGetLocalVector(dm, &locX);
2350: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
2351: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
2352: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
2353: /* Loop over label values */
2354: PetscArrayzero(integral, Nf);
2355: for (v = 0; v < numVals; ++v) {
2356: IS pointIS;
2357: PetscInt numFaces, face;
2358: PetscScalar *fintegral;
2360: DMLabelGetStratumIS(label, vals[v], &pointIS);
2361: if (!pointIS) continue; /* No points with that id on this process */
2362: {
2363: IS isectIS;
2365: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
2366: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
2367: ISDestroy(&pointIS);
2368: pointIS = isectIS;
2369: }
2370: ISGetLocalSize(pointIS, &numFaces);
2371: PetscCalloc1(numFaces*Nf, &fintegral);
2372: DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
2373: /* Sum point contributions into integral */
2374: for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f];
2375: PetscFree(fintegral);
2376: ISDestroy(&pointIS);
2377: }
2378: DMRestoreLocalVector(dm, &locX);
2379: ISDestroy(&facetIS);
2380: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2381: return(0);
2382: }
2384: /*@
2385: DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to a uniformly refined DM.
2387: Input Parameters:
2388: + dmc - The coarse mesh
2389: . dmf - The fine mesh
2390: . isRefined - Flag indicating regular refinement, rather than the same topology
2391: - user - The user context
2393: Output Parameter:
2394: . In - The interpolation matrix
2396: Level: developer
2398: .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2399: @*/
2400: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2401: {
2402: DM_Plex *mesh = (DM_Plex *) dmc->data;
2403: const char *name = "Interpolator";
2404: PetscDS cds, rds;
2405: PetscFE *feRef;
2406: PetscFV *fvRef;
2407: PetscSection fsection, fglobalSection;
2408: PetscSection csection, cglobalSection;
2409: PetscScalar *elemMat;
2410: PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
2411: PetscInt cTotDim, rTotDim = 0;
2412: PetscErrorCode ierr;
2415: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2416: DMGetDimension(dmf, &dim);
2417: DMGetLocalSection(dmf, &fsection);
2418: DMGetGlobalSection(dmf, &fglobalSection);
2419: DMGetLocalSection(dmc, &csection);
2420: DMGetGlobalSection(dmc, &cglobalSection);
2421: PetscSectionGetNumFields(fsection, &Nf);
2422: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
2423: DMGetDS(dmc, &cds);
2424: DMGetDS(dmf, &rds);
2425: PetscCalloc2(Nf, &feRef, Nf, &fvRef);
2426: for (f = 0; f < Nf; ++f) {
2427: PetscObject obj;
2428: PetscClassId id;
2429: PetscInt rNb = 0, Nc = 0;
2431: PetscDSGetDiscretization(rds, f, &obj);
2432: PetscObjectGetClassId(obj, &id);
2433: if (id == PETSCFE_CLASSID) {
2434: PetscFE fe = (PetscFE) obj;
2436: if (isRefined) {
2437: PetscFERefine(fe, &feRef[f]);
2438: } else {
2439: PetscObjectReference((PetscObject) fe);
2440: feRef[f] = fe;
2441: }
2442: PetscFEGetDimension(feRef[f], &rNb);
2443: PetscFEGetNumComponents(fe, &Nc);
2444: } else if (id == PETSCFV_CLASSID) {
2445: PetscFV fv = (PetscFV) obj;
2446: PetscDualSpace Q;
2448: if (isRefined) {
2449: PetscFVRefine(fv, &fvRef[f]);
2450: } else {
2451: PetscObjectReference((PetscObject) fv);
2452: fvRef[f] = fv;
2453: }
2454: PetscFVGetDualSpace(fvRef[f], &Q);
2455: PetscDualSpaceGetDimension(Q, &rNb);
2456: PetscFVGetNumComponents(fv, &Nc);
2457: }
2458: rTotDim += rNb;
2459: }
2460: PetscDSGetTotalDimension(cds, &cTotDim);
2461: PetscMalloc1(rTotDim*cTotDim,&elemMat);
2462: PetscArrayzero(elemMat, rTotDim*cTotDim);
2463: for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2464: PetscDualSpace Qref;
2465: PetscQuadrature f;
2466: const PetscReal *qpoints, *qweights;
2467: PetscReal *points;
2468: PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d;
2470: /* Compose points from all dual basis functionals */
2471: if (feRef[fieldI]) {
2472: PetscFEGetDualSpace(feRef[fieldI], &Qref);
2473: PetscFEGetNumComponents(feRef[fieldI], &Nc);
2474: } else {
2475: PetscFVGetDualSpace(fvRef[fieldI], &Qref);
2476: PetscFVGetNumComponents(fvRef[fieldI], &Nc);
2477: }
2478: PetscDualSpaceGetDimension(Qref, &fpdim);
2479: for (i = 0; i < fpdim; ++i) {
2480: PetscDualSpaceGetFunctional(Qref, i, &f);
2481: PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
2482: npoints += Np;
2483: }
2484: PetscMalloc1(npoints*dim,&points);
2485: for (i = 0, k = 0; i < fpdim; ++i) {
2486: PetscDualSpaceGetFunctional(Qref, i, &f);
2487: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2488: for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
2489: }
2491: for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
2492: PetscObject obj;
2493: PetscClassId id;
2494: PetscInt NcJ = 0, cpdim = 0, j, qNc;
2496: PetscDSGetDiscretization(cds, fieldJ, &obj);
2497: PetscObjectGetClassId(obj, &id);
2498: if (id == PETSCFE_CLASSID) {
2499: PetscFE fe = (PetscFE) obj;
2500: PetscTabulation T = NULL;
2502: /* Evaluate basis at points */
2503: PetscFEGetNumComponents(fe, &NcJ);
2504: PetscFEGetDimension(fe, &cpdim);
2505: /* For now, fields only interpolate themselves */
2506: if (fieldI == fieldJ) {
2507: if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ);
2508: PetscFECreateTabulation(fe, 1, npoints, points, 0, &T);
2509: for (i = 0, k = 0; i < fpdim; ++i) {
2510: PetscDualSpaceGetFunctional(Qref, i, &f);
2511: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2512: if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
2513: for (p = 0; p < Np; ++p, ++k) {
2514: for (j = 0; j < cpdim; ++j) {
2515: /*
2516: cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2517: offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields
2518: fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2519: qNC, Nc, Ncj, c: Number of components in this field
2520: Np, p: Number of quad points in the fine grid functional i
2521: k: i*Np + p, overall point number for the interpolation
2522: */
2523: 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];
2524: }
2525: }
2526: }
2527: PetscTabulationDestroy(&T);
2528: }
2529: } else if (id == PETSCFV_CLASSID) {
2530: PetscFV fv = (PetscFV) obj;
2532: /* Evaluate constant function at points */
2533: PetscFVGetNumComponents(fv, &NcJ);
2534: cpdim = 1;
2535: /* For now, fields only interpolate themselves */
2536: if (fieldI == fieldJ) {
2537: if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ);
2538: for (i = 0, k = 0; i < fpdim; ++i) {
2539: PetscDualSpaceGetFunctional(Qref, i, &f);
2540: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2541: if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
2542: for (p = 0; p < Np; ++p, ++k) {
2543: for (j = 0; j < cpdim; ++j) {
2544: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c];
2545: }
2546: }
2547: }
2548: }
2549: }
2550: offsetJ += cpdim;
2551: }
2552: offsetI += fpdim;
2553: PetscFree(points);
2554: }
2555: if (mesh->printFEM > 1) {DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);}
2556: /* Preallocate matrix */
2557: {
2558: Mat preallocator;
2559: PetscScalar *vals;
2560: PetscInt *cellCIndices, *cellFIndices;
2561: PetscInt locRows, locCols, cell;
2563: MatGetLocalSize(In, &locRows, &locCols);
2564: MatCreate(PetscObjectComm((PetscObject) In), &preallocator);
2565: MatSetType(preallocator, MATPREALLOCATOR);
2566: MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
2567: MatSetUp(preallocator);
2568: PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);
2569: for (cell = cStart; cell < cEnd; ++cell) {
2570: if (isRefined) {
2571: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
2572: MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
2573: } else {
2574: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES);
2575: }
2576: }
2577: PetscFree3(vals,cellCIndices,cellFIndices);
2578: MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
2579: MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
2580: MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
2581: MatDestroy(&preallocator);
2582: }
2583: /* Fill matrix */
2584: MatZeroEntries(In);
2585: for (c = cStart; c < cEnd; ++c) {
2586: if (isRefined) {
2587: DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2588: } else {
2589: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2590: }
2591: }
2592: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);}
2593: PetscFree2(feRef,fvRef);
2594: PetscFree(elemMat);
2595: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2596: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2597: if (mesh->printFEM) {
2598: PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
2599: MatChop(In, 1.0e-10);
2600: MatView(In, NULL);
2601: }
2602: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2603: return(0);
2604: }
2606: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2607: {
2608: SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
2609: }
2611: /*@
2612: DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM.
2614: Input Parameters:
2615: + dmf - The fine mesh
2616: . dmc - The coarse mesh
2617: - user - The user context
2619: Output Parameter:
2620: . In - The interpolation matrix
2622: Level: developer
2624: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
2625: @*/
2626: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2627: {
2628: DM_Plex *mesh = (DM_Plex *) dmf->data;
2629: const char *name = "Interpolator";
2630: PetscDS prob;
2631: PetscSection fsection, csection, globalFSection, globalCSection;
2632: PetscHSetIJ ht;
2633: PetscLayout rLayout;
2634: PetscInt *dnz, *onz;
2635: PetscInt locRows, rStart, rEnd;
2636: PetscReal *x, *v0, *J, *invJ, detJ;
2637: PetscReal *v0c, *Jc, *invJc, detJc;
2638: PetscScalar *elemMat;
2639: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2643: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2644: DMGetCoordinateDim(dmc, &dim);
2645: DMGetDS(dmc, &prob);
2646: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2647: PetscDSGetNumFields(prob, &Nf);
2648: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2649: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2650: DMGetLocalSection(dmf, &fsection);
2651: DMGetGlobalSection(dmf, &globalFSection);
2652: DMGetLocalSection(dmc, &csection);
2653: DMGetGlobalSection(dmc, &globalCSection);
2654: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2655: PetscDSGetTotalDimension(prob, &totDim);
2656: PetscMalloc1(totDim, &elemMat);
2658: MatGetLocalSize(In, &locRows, NULL);
2659: PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);
2660: PetscLayoutSetLocalSize(rLayout, locRows);
2661: PetscLayoutSetBlockSize(rLayout, 1);
2662: PetscLayoutSetUp(rLayout);
2663: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2664: PetscLayoutDestroy(&rLayout);
2665: PetscCalloc2(locRows,&dnz,locRows,&onz);
2666: PetscHSetIJCreate(&ht);
2667: for (field = 0; field < Nf; ++field) {
2668: PetscObject obj;
2669: PetscClassId id;
2670: PetscDualSpace Q = NULL;
2671: PetscQuadrature f;
2672: const PetscReal *qpoints;
2673: PetscInt Nc, Np, fpdim, i, d;
2675: PetscDSGetDiscretization(prob, field, &obj);
2676: PetscObjectGetClassId(obj, &id);
2677: if (id == PETSCFE_CLASSID) {
2678: PetscFE fe = (PetscFE) obj;
2680: PetscFEGetDualSpace(fe, &Q);
2681: PetscFEGetNumComponents(fe, &Nc);
2682: } else if (id == PETSCFV_CLASSID) {
2683: PetscFV fv = (PetscFV) obj;
2685: PetscFVGetDualSpace(fv, &Q);
2686: Nc = 1;
2687: }
2688: PetscDualSpaceGetDimension(Q, &fpdim);
2689: /* For each fine grid cell */
2690: for (cell = cStart; cell < cEnd; ++cell) {
2691: PetscInt *findices, *cindices;
2692: PetscInt numFIndices, numCIndices;
2694: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2695: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2696: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2697: for (i = 0; i < fpdim; ++i) {
2698: Vec pointVec;
2699: PetscScalar *pV;
2700: PetscSF coarseCellSF = NULL;
2701: const PetscSFNode *coarseCells;
2702: PetscInt numCoarseCells, q, c;
2704: /* Get points from the dual basis functional quadrature */
2705: PetscDualSpaceGetFunctional(Q, i, &f);
2706: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2707: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2708: VecSetBlockSize(pointVec, dim);
2709: VecGetArray(pointVec, &pV);
2710: for (q = 0; q < Np; ++q) {
2711: const PetscReal xi0[3] = {-1., -1., -1.};
2713: /* Transform point to real space */
2714: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2715: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2716: }
2717: VecRestoreArray(pointVec, &pV);
2718: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2719: /* OPT: Pack all quad points from fine cell */
2720: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2721: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2722: /* Update preallocation info */
2723: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2724: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2725: {
2726: PetscHashIJKey key;
2727: PetscBool missing;
2729: key.i = findices[i];
2730: if (key.i >= 0) {
2731: /* Get indices for coarse elements */
2732: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2733: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2734: for (c = 0; c < numCIndices; ++c) {
2735: key.j = cindices[c];
2736: if (key.j < 0) continue;
2737: PetscHSetIJQueryAdd(ht, key, &missing);
2738: if (missing) {
2739: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2740: else ++onz[key.i-rStart];
2741: }
2742: }
2743: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2744: }
2745: }
2746: }
2747: PetscSFDestroy(&coarseCellSF);
2748: VecDestroy(&pointVec);
2749: }
2750: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2751: }
2752: }
2753: PetscHSetIJDestroy(&ht);
2754: MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);
2755: MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2756: PetscFree2(dnz,onz);
2757: for (field = 0; field < Nf; ++field) {
2758: PetscObject obj;
2759: PetscClassId id;
2760: PetscDualSpace Q = NULL;
2761: PetscTabulation T = NULL;
2762: PetscQuadrature f;
2763: const PetscReal *qpoints, *qweights;
2764: PetscInt Nc, qNc, Np, fpdim, i, d;
2766: PetscDSGetDiscretization(prob, field, &obj);
2767: PetscObjectGetClassId(obj, &id);
2768: if (id == PETSCFE_CLASSID) {
2769: PetscFE fe = (PetscFE) obj;
2771: PetscFEGetDualSpace(fe, &Q);
2772: PetscFEGetNumComponents(fe, &Nc);
2773: PetscFECreateTabulation(fe, 1, 1, x, 0, &T);
2774: } else if (id == PETSCFV_CLASSID) {
2775: PetscFV fv = (PetscFV) obj;
2777: PetscFVGetDualSpace(fv, &Q);
2778: Nc = 1;
2779: } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field);
2780: PetscDualSpaceGetDimension(Q, &fpdim);
2781: /* For each fine grid cell */
2782: for (cell = cStart; cell < cEnd; ++cell) {
2783: PetscInt *findices, *cindices;
2784: PetscInt numFIndices, numCIndices;
2786: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2787: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2788: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2789: for (i = 0; i < fpdim; ++i) {
2790: Vec pointVec;
2791: PetscScalar *pV;
2792: PetscSF coarseCellSF = NULL;
2793: const PetscSFNode *coarseCells;
2794: PetscInt numCoarseCells, cpdim, q, c, j;
2796: /* Get points from the dual basis functional quadrature */
2797: PetscDualSpaceGetFunctional(Q, i, &f);
2798: PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2799: if (qNc != Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, Nc);
2800: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2801: VecSetBlockSize(pointVec, dim);
2802: VecGetArray(pointVec, &pV);
2803: for (q = 0; q < Np; ++q) {
2804: const PetscReal xi0[3] = {-1., -1., -1.};
2806: /* Transform point to real space */
2807: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2808: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2809: }
2810: VecRestoreArray(pointVec, &pV);
2811: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2812: /* OPT: Read this out from preallocation information */
2813: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2814: /* Update preallocation info */
2815: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2816: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2817: VecGetArray(pointVec, &pV);
2818: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2819: PetscReal pVReal[3];
2820: const PetscReal xi0[3] = {-1., -1., -1.};
2822: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2823: /* Transform points from real space to coarse reference space */
2824: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2825: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2826: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
2828: if (id == PETSCFE_CLASSID) {
2829: PetscFE fe = (PetscFE) obj;
2831: /* Evaluate coarse basis on contained point */
2832: PetscFEGetDimension(fe, &cpdim);
2833: PetscFEComputeTabulation(fe, 1, x, 0, T);
2834: PetscArrayzero(elemMat, cpdim);
2835: /* Get elemMat entries by multiplying by weight */
2836: for (j = 0; j < cpdim; ++j) {
2837: for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*qweights[ccell*qNc + c];
2838: }
2839: } else {
2840: cpdim = 1;
2841: for (j = 0; j < cpdim; ++j) {
2842: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c];
2843: }
2844: }
2845: /* Update interpolator */
2846: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2847: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2848: MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);
2849: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2850: }
2851: VecRestoreArray(pointVec, &pV);
2852: PetscSFDestroy(&coarseCellSF);
2853: VecDestroy(&pointVec);
2854: }
2855: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2856: }
2857: if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
2858: }
2859: PetscFree3(v0,J,invJ);
2860: PetscFree3(v0c,Jc,invJc);
2861: PetscFree(elemMat);
2862: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2863: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2864: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2865: return(0);
2866: }
2868: /*@
2869: DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM.
2871: Input Parameters:
2872: + dmf - The fine mesh
2873: . dmc - The coarse mesh
2874: - user - The user context
2876: Output Parameter:
2877: . mass - The mass matrix
2879: Level: developer
2881: .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2882: @*/
2883: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2884: {
2885: DM_Plex *mesh = (DM_Plex *) dmf->data;
2886: const char *name = "Mass Matrix";
2887: PetscDS prob;
2888: PetscSection fsection, csection, globalFSection, globalCSection;
2889: PetscHSetIJ ht;
2890: PetscLayout rLayout;
2891: PetscInt *dnz, *onz;
2892: PetscInt locRows, rStart, rEnd;
2893: PetscReal *x, *v0, *J, *invJ, detJ;
2894: PetscReal *v0c, *Jc, *invJc, detJc;
2895: PetscScalar *elemMat;
2896: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2900: DMGetCoordinateDim(dmc, &dim);
2901: DMGetDS(dmc, &prob);
2902: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2903: PetscDSGetNumFields(prob, &Nf);
2904: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2905: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2906: DMGetLocalSection(dmf, &fsection);
2907: DMGetGlobalSection(dmf, &globalFSection);
2908: DMGetLocalSection(dmc, &csection);
2909: DMGetGlobalSection(dmc, &globalCSection);
2910: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2911: PetscDSGetTotalDimension(prob, &totDim);
2912: PetscMalloc1(totDim, &elemMat);
2914: MatGetLocalSize(mass, &locRows, NULL);
2915: PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);
2916: PetscLayoutSetLocalSize(rLayout, locRows);
2917: PetscLayoutSetBlockSize(rLayout, 1);
2918: PetscLayoutSetUp(rLayout);
2919: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2920: PetscLayoutDestroy(&rLayout);
2921: PetscCalloc2(locRows,&dnz,locRows,&onz);
2922: PetscHSetIJCreate(&ht);
2923: for (field = 0; field < Nf; ++field) {
2924: PetscObject obj;
2925: PetscClassId id;
2926: PetscQuadrature quad;
2927: const PetscReal *qpoints;
2928: PetscInt Nq, Nc, i, d;
2930: PetscDSGetDiscretization(prob, field, &obj);
2931: PetscObjectGetClassId(obj, &id);
2932: if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);}
2933: else {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2934: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2935: /* For each fine grid cell */
2936: for (cell = cStart; cell < cEnd; ++cell) {
2937: Vec pointVec;
2938: PetscScalar *pV;
2939: PetscSF coarseCellSF = NULL;
2940: const PetscSFNode *coarseCells;
2941: PetscInt numCoarseCells, q, c;
2942: PetscInt *findices, *cindices;
2943: PetscInt numFIndices, numCIndices;
2945: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2946: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2947: /* Get points from the quadrature */
2948: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2949: VecSetBlockSize(pointVec, dim);
2950: VecGetArray(pointVec, &pV);
2951: for (q = 0; q < Nq; ++q) {
2952: const PetscReal xi0[3] = {-1., -1., -1.};
2954: /* Transform point to real space */
2955: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2956: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2957: }
2958: VecRestoreArray(pointVec, &pV);
2959: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2960: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2961: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2962: /* Update preallocation info */
2963: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2964: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2965: {
2966: PetscHashIJKey key;
2967: PetscBool missing;
2969: for (i = 0; i < numFIndices; ++i) {
2970: key.i = findices[i];
2971: if (key.i >= 0) {
2972: /* Get indices for coarse elements */
2973: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2974: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2975: for (c = 0; c < numCIndices; ++c) {
2976: key.j = cindices[c];
2977: if (key.j < 0) continue;
2978: PetscHSetIJQueryAdd(ht, key, &missing);
2979: if (missing) {
2980: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2981: else ++onz[key.i-rStart];
2982: }
2983: }
2984: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2985: }
2986: }
2987: }
2988: }
2989: PetscSFDestroy(&coarseCellSF);
2990: VecDestroy(&pointVec);
2991: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2992: }
2993: }
2994: PetscHSetIJDestroy(&ht);
2995: MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
2996: MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2997: PetscFree2(dnz,onz);
2998: for (field = 0; field < Nf; ++field) {
2999: PetscObject obj;
3000: PetscClassId id;
3001: PetscTabulation T, Tfine;
3002: PetscQuadrature quad;
3003: const PetscReal *qpoints, *qweights;
3004: PetscInt Nq, Nc, i, d;
3006: PetscDSGetDiscretization(prob, field, &obj);
3007: PetscObjectGetClassId(obj, &id);
3008: if (id == PETSCFE_CLASSID) {
3009: PetscFEGetQuadrature((PetscFE) obj, &quad);
3010: PetscFEGetCellTabulation((PetscFE) obj, &Tfine);
3011: PetscFECreateTabulation((PetscFE) obj, 1, 1, x, 0, &T);
3012: } else {
3013: PetscFVGetQuadrature((PetscFV) obj, &quad);
3014: }
3015: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
3016: /* For each fine grid cell */
3017: for (cell = cStart; cell < cEnd; ++cell) {
3018: Vec pointVec;
3019: PetscScalar *pV;
3020: PetscSF coarseCellSF = NULL;
3021: const PetscSFNode *coarseCells;
3022: PetscInt numCoarseCells, cpdim, q, c, j;
3023: PetscInt *findices, *cindices;
3024: PetscInt numFIndices, numCIndices;
3026: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3027: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
3028: /* Get points from the quadrature */
3029: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
3030: VecSetBlockSize(pointVec, dim);
3031: VecGetArray(pointVec, &pV);
3032: for (q = 0; q < Nq; ++q) {
3033: const PetscReal xi0[3] = {-1., -1., -1.};
3035: /* Transform point to real space */
3036: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
3037: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
3038: }
3039: VecRestoreArray(pointVec, &pV);
3040: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
3041: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
3042: /* Update matrix */
3043: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
3044: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
3045: VecGetArray(pointVec, &pV);
3046: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3047: PetscReal pVReal[3];
3048: const PetscReal xi0[3] = {-1., -1., -1.};
3051: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3052: /* Transform points from real space to coarse reference space */
3053: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
3054: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
3055: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3057: if (id == PETSCFE_CLASSID) {
3058: PetscFE fe = (PetscFE) obj;
3060: /* Evaluate coarse basis on contained point */
3061: PetscFEGetDimension(fe, &cpdim);
3062: PetscFEComputeTabulation(fe, 1, x, 0, T);
3063: /* Get elemMat entries by multiplying by weight */
3064: for (i = 0; i < numFIndices; ++i) {
3065: PetscArrayzero(elemMat, cpdim);
3066: for (j = 0; j < cpdim; ++j) {
3067: 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;
3068: }
3069: /* Update interpolator */
3070: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3071: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3072: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3073: }
3074: } else {
3075: cpdim = 1;
3076: for (i = 0; i < numFIndices; ++i) {
3077: PetscArrayzero(elemMat, cpdim);
3078: for (j = 0; j < cpdim; ++j) {
3079: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ;
3080: }
3081: /* Update interpolator */
3082: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3083: PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);
3084: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3085: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3086: }
3087: }
3088: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3089: }
3090: VecRestoreArray(pointVec, &pV);
3091: PetscSFDestroy(&coarseCellSF);
3092: VecDestroy(&pointVec);
3093: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3094: }
3095: if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
3096: }
3097: PetscFree3(v0,J,invJ);
3098: PetscFree3(v0c,Jc,invJc);
3099: PetscFree(elemMat);
3100: MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
3101: MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
3102: return(0);
3103: }
3105: /*@
3106: DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
3108: Input Parameters:
3109: + dmc - The coarse mesh
3110: - dmf - The fine mesh
3111: - user - The user context
3113: Output Parameter:
3114: . sc - The mapping
3116: Level: developer
3118: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
3119: @*/
3120: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3121: {
3122: PetscDS prob;
3123: PetscFE *feRef;
3124: PetscFV *fvRef;
3125: Vec fv, cv;
3126: IS fis, cis;
3127: PetscSection fsection, fglobalSection, csection, cglobalSection;
3128: PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3129: PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
3130: PetscBool *needAvg;
3134: PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3135: DMGetDimension(dmf, &dim);
3136: DMGetLocalSection(dmf, &fsection);
3137: DMGetGlobalSection(dmf, &fglobalSection);
3138: DMGetLocalSection(dmc, &csection);
3139: DMGetGlobalSection(dmc, &cglobalSection);
3140: PetscSectionGetNumFields(fsection, &Nf);
3141: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
3142: DMGetDS(dmc, &prob);
3143: PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);
3144: for (f = 0; f < Nf; ++f) {
3145: PetscObject obj;
3146: PetscClassId id;
3147: PetscInt fNb = 0, Nc = 0;
3149: PetscDSGetDiscretization(prob, f, &obj);
3150: PetscObjectGetClassId(obj, &id);
3151: if (id == PETSCFE_CLASSID) {
3152: PetscFE fe = (PetscFE) obj;
3153: PetscSpace sp;
3154: PetscInt maxDegree;
3156: PetscFERefine(fe, &feRef[f]);
3157: PetscFEGetDimension(feRef[f], &fNb);
3158: PetscFEGetNumComponents(fe, &Nc);
3159: PetscFEGetBasisSpace(fe, &sp);
3160: PetscSpaceGetDegree(sp, NULL, &maxDegree);
3161: if (!maxDegree) needAvg[f] = PETSC_TRUE;
3162: } else if (id == PETSCFV_CLASSID) {
3163: PetscFV fv = (PetscFV) obj;
3164: PetscDualSpace Q;
3166: PetscFVRefine(fv, &fvRef[f]);
3167: PetscFVGetDualSpace(fvRef[f], &Q);
3168: PetscDualSpaceGetDimension(Q, &fNb);
3169: PetscFVGetNumComponents(fv, &Nc);
3170: needAvg[f] = PETSC_TRUE;
3171: }
3172: fTotDim += fNb;
3173: }
3174: PetscDSGetTotalDimension(prob, &cTotDim);
3175: PetscMalloc1(cTotDim,&cmap);
3176: for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
3177: PetscFE feC;
3178: PetscFV fvC;
3179: PetscDualSpace QF, QC;
3180: PetscInt order = -1, NcF, NcC, fpdim, cpdim;
3182: if (feRef[field]) {
3183: PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);
3184: PetscFEGetNumComponents(feC, &NcC);
3185: PetscFEGetNumComponents(feRef[field], &NcF);
3186: PetscFEGetDualSpace(feRef[field], &QF);
3187: PetscDualSpaceGetOrder(QF, &order);
3188: PetscDualSpaceGetDimension(QF, &fpdim);
3189: PetscFEGetDualSpace(feC, &QC);
3190: PetscDualSpaceGetDimension(QC, &cpdim);
3191: } else {
3192: PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);
3193: PetscFVGetNumComponents(fvC, &NcC);
3194: PetscFVGetNumComponents(fvRef[field], &NcF);
3195: PetscFVGetDualSpace(fvRef[field], &QF);
3196: PetscDualSpaceGetDimension(QF, &fpdim);
3197: PetscFVGetDualSpace(fvC, &QC);
3198: PetscDualSpaceGetDimension(QC, &cpdim);
3199: }
3200: if (NcF != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", NcF, NcC);
3201: for (c = 0; c < cpdim; ++c) {
3202: PetscQuadrature cfunc;
3203: const PetscReal *cqpoints, *cqweights;
3204: PetscInt NqcC, NpC;
3205: PetscBool found = PETSC_FALSE;
3207: PetscDualSpaceGetFunctional(QC, c, &cfunc);
3208: PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
3209: if (NqcC != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcC, NcC);
3210: if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
3211: for (f = 0; f < fpdim; ++f) {
3212: PetscQuadrature ffunc;
3213: const PetscReal *fqpoints, *fqweights;
3214: PetscReal sum = 0.0;
3215: PetscInt NqcF, NpF;
3217: PetscDualSpaceGetFunctional(QF, f, &ffunc);
3218: PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
3219: if (NqcF != NcF) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcF, NcF);
3220: if (NpC != NpF) continue;
3221: for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
3222: if (sum > 1.0e-9) continue;
3223: for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
3224: if (sum < 1.0e-9) continue;
3225: cmap[offsetC+c] = offsetF+f;
3226: found = PETSC_TRUE;
3227: break;
3228: }
3229: if (!found) {
3230: /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3231: if (fvRef[field] || (feRef[field] && order == 0)) {
3232: cmap[offsetC+c] = offsetF+0;
3233: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3234: }
3235: }
3236: offsetC += cpdim;
3237: offsetF += fpdim;
3238: }
3239: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
3240: PetscFree3(feRef,fvRef,needAvg);
3242: DMGetGlobalVector(dmf, &fv);
3243: DMGetGlobalVector(dmc, &cv);
3244: VecGetOwnershipRange(cv, &startC, &endC);
3245: PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
3246: PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);
3247: PetscMalloc1(m,&cindices);
3248: PetscMalloc1(m,&findices);
3249: for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
3250: for (c = cStart; c < cEnd; ++c) {
3251: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
3252: for (d = 0; d < cTotDim; ++d) {
3253: if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3254: if ((findices[cellCIndices[d]-startC] >= 0) && (findices[cellCIndices[d]-startC] != cellFIndices[cmap[d]])) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %D maps to both %D and %D", cindices[cellCIndices[d]-startC], findices[cellCIndices[d]-startC], cellFIndices[cmap[d]]);
3255: cindices[cellCIndices[d]-startC] = cellCIndices[d];
3256: findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
3257: }
3258: }
3259: PetscFree(cmap);
3260: PetscFree2(cellCIndices,cellFIndices);
3262: ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
3263: ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
3264: VecScatterCreate(cv, cis, fv, fis, sc);
3265: ISDestroy(&cis);
3266: ISDestroy(&fis);
3267: DMRestoreGlobalVector(dmf, &fv);
3268: DMRestoreGlobalVector(dmc, &cv);
3269: PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3270: return(0);
3271: }
3273: /*@C
3274: DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
3276: Input Parameters:
3277: + dm - The DM
3278: . cellIS - The cells to include
3279: . locX - A local vector with the solution fields
3280: . locX_t - A local vector with solution field time derivatives, or NULL
3281: - locA - A local vector with auxiliary fields, or NULL
3283: Output Parameters:
3284: + u - The field coefficients
3285: . u_t - The fields derivative coefficients
3286: - a - The auxiliary field coefficients
3288: Level: developer
3290: .seealso: DMPlexGetFaceFields()
3291: @*/
3292: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3293: {
3294: DM plex, plexA = NULL;
3295: DMEnclosureType encAux;
3296: PetscSection section, sectionAux;
3297: PetscDS prob;
3298: const PetscInt *cells;
3299: PetscInt cStart, cEnd, numCells, totDim, totDimAux, c;
3300: PetscErrorCode ierr;
3310: DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
3311: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3312: DMGetLocalSection(dm, §ion);
3313: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
3314: PetscDSGetTotalDimension(prob, &totDim);
3315: if (locA) {
3316: DM dmAux;
3317: PetscDS probAux;
3319: VecGetDM(locA, &dmAux);
3320: DMGetEnclosureRelation(dmAux, dm, &encAux);
3321: DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3322: DMGetLocalSection(dmAux, §ionAux);
3323: DMGetDS(dmAux, &probAux);
3324: PetscDSGetTotalDimension(probAux, &totDimAux);
3325: }
3326: numCells = cEnd - cStart;
3327: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);
3328: if (locX_t) {DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);} else {*u_t = NULL;}
3329: if (locA) {DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);} else {*a = NULL;}
3330: for (c = cStart; c < cEnd; ++c) {
3331: const PetscInt cell = cells ? cells[c] : c;
3332: const PetscInt cind = c - cStart;
3333: PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
3334: PetscInt i;
3336: DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
3337: for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i];
3338: DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
3339: if (locX_t) {
3340: DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
3341: for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i];
3342: DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
3343: }
3344: if (locA) {
3345: PetscInt subcell;
3346: DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell);
3347: DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3348: for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i];
3349: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3350: }
3351: }
3352: DMDestroy(&plex);
3353: if (locA) {DMDestroy(&plexA);}
3354: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3355: return(0);
3356: }
3358: /*@C
3359: DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
3361: Input Parameters:
3362: + dm - The DM
3363: . cellIS - The cells to include
3364: . locX - A local vector with the solution fields
3365: . locX_t - A local vector with solution field time derivatives, or NULL
3366: - locA - A local vector with auxiliary fields, or NULL
3368: Output Parameters:
3369: + u - The field coefficients
3370: . u_t - The fields derivative coefficients
3371: - a - The auxiliary field coefficients
3373: Level: developer
3375: .seealso: DMPlexGetFaceFields()
3376: @*/
3377: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3378: {
3382: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
3383: if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
3384: if (locA) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
3385: return(0);
3386: }
3388: /*@C
3389: DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
3391: Input Parameters:
3392: + dm - The DM
3393: . fStart - The first face to include
3394: . fEnd - The first face to exclude
3395: . locX - A local vector with the solution fields
3396: . locX_t - A local vector with solution field time derivatives, or NULL
3397: . faceGeometry - A local vector with face geometry
3398: . cellGeometry - A local vector with cell geometry
3399: - locaGrad - A local vector with field gradients, or NULL
3401: Output Parameters:
3402: + Nface - The number of faces with field values
3403: . uL - The field values at the left side of the face
3404: - uR - The field values at the right side of the face
3406: Level: developer
3408: .seealso: DMPlexGetCellFields()
3409: @*/
3410: 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)
3411: {
3412: DM dmFace, dmCell, dmGrad = NULL;
3413: PetscSection section;
3414: PetscDS prob;
3415: DMLabel ghostLabel;
3416: const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
3417: PetscBool *isFE;
3418: PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
3419: PetscErrorCode ierr;
3430: DMGetDimension(dm, &dim);
3431: DMGetDS(dm, &prob);
3432: DMGetLocalSection(dm, §ion);
3433: PetscDSGetNumFields(prob, &Nf);
3434: PetscDSGetTotalComponents(prob, &Nc);
3435: PetscMalloc1(Nf, &isFE);
3436: for (f = 0; f < Nf; ++f) {
3437: PetscObject obj;
3438: PetscClassId id;
3440: PetscDSGetDiscretization(prob, f, &obj);
3441: PetscObjectGetClassId(obj, &id);
3442: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
3443: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3444: else {isFE[f] = PETSC_FALSE;}
3445: }
3446: DMGetLabel(dm, "ghost", &ghostLabel);
3447: VecGetArrayRead(locX, &x);
3448: VecGetDM(faceGeometry, &dmFace);
3449: VecGetArrayRead(faceGeometry, &facegeom);
3450: VecGetDM(cellGeometry, &dmCell);
3451: VecGetArrayRead(cellGeometry, &cellgeom);
3452: if (locGrad) {
3453: VecGetDM(locGrad, &dmGrad);
3454: VecGetArrayRead(locGrad, &lgrad);
3455: }
3456: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
3457: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
3458: /* Right now just eat the extra work for FE (could make a cell loop) */
3459: for (face = fStart, iface = 0; face < fEnd; ++face) {
3460: const PetscInt *cells;
3461: PetscFVFaceGeom *fg;
3462: PetscFVCellGeom *cgL, *cgR;
3463: PetscScalar *xL, *xR, *gL, *gR;
3464: PetscScalar *uLl = *uL, *uRl = *uR;
3465: PetscInt ghost, nsupp, nchild;
3467: DMLabelGetValue(ghostLabel, face, &ghost);
3468: DMPlexGetSupportSize(dm, face, &nsupp);
3469: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3470: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3471: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3472: DMPlexGetSupport(dm, face, &cells);
3473: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3474: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3475: for (f = 0; f < Nf; ++f) {
3476: PetscInt off;
3478: PetscDSGetComponentOffset(prob, f, &off);
3479: if (isFE[f]) {
3480: const PetscInt *cone;
3481: PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
3483: xL = xR = NULL;
3484: PetscSectionGetFieldComponents(section, f, &comp);
3485: DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3486: DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3487: DMPlexGetCone(dm, cells[0], &cone);
3488: DMPlexGetConeSize(dm, cells[0], &coneSizeL);
3489: for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
3490: DMPlexGetCone(dm, cells[1], &cone);
3491: DMPlexGetConeSize(dm, cells[1], &coneSizeR);
3492: for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
3493: if (faceLocL == coneSizeL && faceLocR == coneSizeR) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D or cell %D", face, cells[0], cells[1]);
3494: /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
3495: /* TODO: this is a hack that might not be right for nonconforming */
3496: if (faceLocL < coneSizeL) {
3497: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
3498: if (rdof == ldof && faceLocR < coneSizeR) {PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
3499: else {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
3500: }
3501: else {
3502: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
3503: PetscSectionGetFieldComponents(section, f, &comp);
3504: for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
3505: }
3506: DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3507: DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3508: } else {
3509: PetscFV fv;
3510: PetscInt numComp, c;
3512: PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
3513: PetscFVGetNumComponents(fv, &numComp);
3514: DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3515: DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3516: if (dmGrad) {
3517: PetscReal dxL[3], dxR[3];
3519: DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
3520: DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
3521: DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
3522: DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
3523: for (c = 0; c < numComp; ++c) {
3524: uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
3525: uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
3526: }
3527: } else {
3528: for (c = 0; c < numComp; ++c) {
3529: uLl[iface*Nc+off+c] = xL[c];
3530: uRl[iface*Nc+off+c] = xR[c];
3531: }
3532: }
3533: }
3534: }
3535: ++iface;
3536: }
3537: *Nface = iface;
3538: VecRestoreArrayRead(locX, &x);
3539: VecRestoreArrayRead(faceGeometry, &facegeom);
3540: VecRestoreArrayRead(cellGeometry, &cellgeom);
3541: if (locGrad) {
3542: VecRestoreArrayRead(locGrad, &lgrad);
3543: }
3544: PetscFree(isFE);
3545: return(0);
3546: }
3548: /*@C
3549: DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
3551: Input Parameters:
3552: + dm - The DM
3553: . fStart - The first face to include
3554: . fEnd - The first face to exclude
3555: . locX - A local vector with the solution fields
3556: . locX_t - A local vector with solution field time derivatives, or NULL
3557: . faceGeometry - A local vector with face geometry
3558: . cellGeometry - A local vector with cell geometry
3559: - locaGrad - A local vector with field gradients, or NULL
3561: Output Parameters:
3562: + Nface - The number of faces with field values
3563: . uL - The field values at the left side of the face
3564: - uR - The field values at the right side of the face
3566: Level: developer
3568: .seealso: DMPlexGetFaceFields()
3569: @*/
3570: 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)
3571: {
3575: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3576: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3577: return(0);
3578: }
3580: /*@C
3581: DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
3583: Input Parameters:
3584: + dm - The DM
3585: . fStart - The first face to include
3586: . fEnd - The first face to exclude
3587: . faceGeometry - A local vector with face geometry
3588: - cellGeometry - A local vector with cell geometry
3590: Output Parameters:
3591: + Nface - The number of faces with field values
3592: . fgeom - The extract the face centroid and normal
3593: - vol - The cell volume
3595: Level: developer
3597: .seealso: DMPlexGetCellFields()
3598: @*/
3599: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3600: {
3601: DM dmFace, dmCell;
3602: DMLabel ghostLabel;
3603: const PetscScalar *facegeom, *cellgeom;
3604: PetscInt dim, numFaces = fEnd - fStart, iface, face;
3605: PetscErrorCode ierr;
3613: DMGetDimension(dm, &dim);
3614: DMGetLabel(dm, "ghost", &ghostLabel);
3615: VecGetDM(faceGeometry, &dmFace);
3616: VecGetArrayRead(faceGeometry, &facegeom);
3617: VecGetDM(cellGeometry, &dmCell);
3618: VecGetArrayRead(cellGeometry, &cellgeom);
3619: PetscMalloc1(numFaces, fgeom);
3620: DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
3621: for (face = fStart, iface = 0; face < fEnd; ++face) {
3622: const PetscInt *cells;
3623: PetscFVFaceGeom *fg;
3624: PetscFVCellGeom *cgL, *cgR;
3625: PetscFVFaceGeom *fgeoml = *fgeom;
3626: PetscReal *voll = *vol;
3627: PetscInt ghost, d, nchild, nsupp;
3629: DMLabelGetValue(ghostLabel, face, &ghost);
3630: DMPlexGetSupportSize(dm, face, &nsupp);
3631: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3632: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3633: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3634: DMPlexGetSupport(dm, face, &cells);
3635: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3636: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3637: for (d = 0; d < dim; ++d) {
3638: fgeoml[iface].centroid[d] = fg->centroid[d];
3639: fgeoml[iface].normal[d] = fg->normal[d];
3640: }
3641: voll[iface*2+0] = cgL->volume;
3642: voll[iface*2+1] = cgR->volume;
3643: ++iface;
3644: }
3645: *Nface = iface;
3646: VecRestoreArrayRead(faceGeometry, &facegeom);
3647: VecRestoreArrayRead(cellGeometry, &cellgeom);
3648: return(0);
3649: }
3651: /*@C
3652: DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
3654: Input Parameters:
3655: + dm - The DM
3656: . fStart - The first face to include
3657: . fEnd - The first face to exclude
3658: . faceGeometry - A local vector with face geometry
3659: - cellGeometry - A local vector with cell geometry
3661: Output Parameters:
3662: + Nface - The number of faces with field values
3663: . fgeom - The extract the face centroid and normal
3664: - vol - The cell volume
3666: Level: developer
3668: .seealso: DMPlexGetFaceFields()
3669: @*/
3670: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3671: {
3675: PetscFree(*fgeom);
3676: DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3677: return(0);
3678: }
3680: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3681: {
3682: char composeStr[33] = {0};
3683: PetscObjectId id;
3684: PetscContainer container;
3685: PetscErrorCode ierr;
3688: PetscObjectGetId((PetscObject)quad,&id);
3689: PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3690: PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3691: if (container) {
3692: PetscContainerGetPointer(container, (void **) geom);
3693: } else {
3694: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3695: PetscContainerCreate(PETSC_COMM_SELF,&container);
3696: PetscContainerSetPointer(container, (void *) *geom);
3697: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3698: PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3699: PetscContainerDestroy(&container);
3700: }
3701: return(0);
3702: }
3704: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3705: {
3707: *geom = NULL;
3708: return(0);
3709: }
3711: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3712: {
3713: DM_Plex *mesh = (DM_Plex *) dm->data;
3714: const char *name = "Residual";
3715: DM dmAux = NULL;
3716: DMLabel ghostLabel = NULL;
3717: PetscDS prob = NULL;
3718: PetscDS probAux = NULL;
3719: PetscBool useFEM = PETSC_FALSE;
3720: PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3721: DMField coordField = NULL;
3722: Vec locA;
3723: PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3724: IS chunkIS;
3725: const PetscInt *cells;
3726: PetscInt cStart, cEnd, numCells;
3727: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3728: PetscInt maxDegree = PETSC_MAX_INT;
3729: PetscQuadrature affineQuad = NULL, *quads = NULL;
3730: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
3731: PetscErrorCode ierr;
3734: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3735: /* FEM+FVM */
3736: /* 1: Get sizes from dm and dmAux */
3737: DMGetLabel(dm, "ghost", &ghostLabel);
3738: DMGetDS(dm, &prob);
3739: PetscDSGetNumFields(prob, &Nf);
3740: PetscDSGetTotalDimension(prob, &totDim);
3741: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
3742: if (locA) {
3743: VecGetDM(locA, &dmAux);
3744: DMGetDS(dmAux, &probAux);
3745: PetscDSGetTotalDimension(probAux, &totDimAux);
3746: }
3747: /* 2: Get geometric data */
3748: for (f = 0; f < Nf; ++f) {
3749: PetscObject obj;
3750: PetscClassId id;
3751: PetscBool fimp;
3753: PetscDSGetImplicit(prob, f, &fimp);
3754: if (isImplicit != fimp) continue;
3755: PetscDSGetDiscretization(prob, f, &obj);
3756: PetscObjectGetClassId(obj, &id);
3757: if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3758: if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3759: }
3760: if (useFEM) {
3761: DMGetCoordinateField(dm, &coordField);
3762: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3763: if (maxDegree <= 1) {
3764: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3765: if (affineQuad) {
3766: DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3767: }
3768: } else {
3769: PetscCalloc2(Nf,&quads,Nf,&geoms);
3770: for (f = 0; f < Nf; ++f) {
3771: PetscObject obj;
3772: PetscClassId id;
3773: PetscBool fimp;
3775: PetscDSGetImplicit(prob, f, &fimp);
3776: if (isImplicit != fimp) continue;
3777: PetscDSGetDiscretization(prob, f, &obj);
3778: PetscObjectGetClassId(obj, &id);
3779: if (id == PETSCFE_CLASSID) {
3780: PetscFE fe = (PetscFE) obj;
3782: PetscFEGetQuadrature(fe, &quads[f]);
3783: PetscObjectReference((PetscObject)quads[f]);
3784: DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3785: }
3786: }
3787: }
3788: }
3789: /* Loop over chunks */
3790: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3791: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3792: if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3793: numCells = cEnd - cStart;
3794: numChunks = 1;
3795: cellChunkSize = numCells/numChunks;
3796: numChunks = PetscMin(1,numCells);
3797: for (chunk = 0; chunk < numChunks; ++chunk) {
3798: PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL;
3799: PetscReal *vol = NULL;
3800: PetscFVFaceGeom *fgeom = NULL;
3801: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3802: PetscInt numFaces = 0;
3804: /* Extract field coefficients */
3805: if (useFEM) {
3806: ISGetPointSubrange(chunkIS, cS, cE, cells);
3807: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3808: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3809: PetscArrayzero(elemVec, numCells*totDim);
3810: }
3811: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3812: /* Loop over fields */
3813: for (f = 0; f < Nf; ++f) {
3814: PetscObject obj;
3815: PetscClassId id;
3816: PetscBool fimp;
3817: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
3819: PetscDSGetImplicit(prob, f, &fimp);
3820: if (isImplicit != fimp) continue;
3821: PetscDSGetDiscretization(prob, f, &obj);
3822: PetscObjectGetClassId(obj, &id);
3823: if (id == PETSCFE_CLASSID) {
3824: PetscFE fe = (PetscFE) obj;
3825: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
3826: PetscFEGeom *chunkGeom = NULL;
3827: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3828: PetscInt Nq, Nb;
3830: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3831: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3832: PetscFEGetDimension(fe, &Nb);
3833: blockSize = Nb;
3834: batchSize = numBlocks * blockSize;
3835: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3836: numChunks = numCells / (numBatches*batchSize);
3837: Ne = numChunks*numBatches*batchSize;
3838: Nr = numCells % (numBatches*batchSize);
3839: offset = numCells - Nr;
3840: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3841: /* 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) */
3842: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3843: PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3844: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3845: PetscFEIntegrateResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3846: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3847: } else if (id == PETSCFV_CLASSID) {
3848: PetscFV fv = (PetscFV) obj;
3850: Ne = numFaces;
3851: /* Riemann solve over faces (need fields at face centroids) */
3852: /* We need to evaluate FE fields at those coordinates */
3853: PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3854: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
3855: }
3856: /* Loop over domain */
3857: if (useFEM) {
3858: /* Add elemVec to locX */
3859: for (c = cS; c < cE; ++c) {
3860: const PetscInt cell = cells ? cells[c] : c;
3861: const PetscInt cind = c - cStart;
3863: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
3864: if (ghostLabel) {
3865: PetscInt ghostVal;
3867: DMLabelGetValue(ghostLabel,cell,&ghostVal);
3868: if (ghostVal > 0) continue;
3869: }
3870: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3871: }
3872: }
3873: /* Handle time derivative */
3874: if (locX_t) {
3875: PetscScalar *x_t, *fa;
3877: VecGetArray(locF, &fa);
3878: VecGetArray(locX_t, &x_t);
3879: for (f = 0; f < Nf; ++f) {
3880: PetscFV fv;
3881: PetscObject obj;
3882: PetscClassId id;
3883: PetscInt pdim, d;
3885: PetscDSGetDiscretization(prob, f, &obj);
3886: PetscObjectGetClassId(obj, &id);
3887: if (id != PETSCFV_CLASSID) continue;
3888: fv = (PetscFV) obj;
3889: PetscFVGetNumComponents(fv, &pdim);
3890: for (c = cS; c < cE; ++c) {
3891: const PetscInt cell = cells ? cells[c] : c;
3892: PetscScalar *u_t, *r;
3894: if (ghostLabel) {
3895: PetscInt ghostVal;
3897: DMLabelGetValue(ghostLabel, cell, &ghostVal);
3898: if (ghostVal > 0) continue;
3899: }
3900: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3901: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3902: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3903: }
3904: }
3905: VecRestoreArray(locX_t, &x_t);
3906: VecRestoreArray(locF, &fa);
3907: }
3908: if (useFEM) {
3909: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3910: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3911: }
3912: }
3913: if (useFEM) {ISDestroy(&chunkIS);}
3914: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3915: /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3916: if (useFEM) {
3917: if (maxDegree <= 1) {
3918: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3919: PetscQuadratureDestroy(&affineQuad);
3920: } else {
3921: for (f = 0; f < Nf; ++f) {
3922: DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3923: PetscQuadratureDestroy(&quads[f]);
3924: }
3925: PetscFree2(quads,geoms);
3926: }
3927: }
3928: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
3929: return(0);
3930: }
3932: /*
3933: 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
3935: X - The local solution vector
3936: X_t - The local solution time derviative vector, or NULL
3937: */
3938: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
3939: PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
3940: {
3941: DM_Plex *mesh = (DM_Plex *) dm->data;
3942: const char *name = "Jacobian", *nameP = "JacobianPre";
3943: DM dmAux = NULL;
3944: PetscDS prob, probAux = NULL;
3945: PetscSection sectionAux = NULL;
3946: Vec A;
3947: DMField coordField;
3948: PetscFEGeom *cgeomFEM;
3949: PetscQuadrature qGeom = NULL;
3950: Mat J = Jac, JP = JacP;
3951: PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
3952: PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
3953: const PetscInt *cells;
3954: PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
3955: PetscErrorCode ierr;
3958: CHKMEMQ;
3959: ISGetLocalSize(cellIS, &numCells);
3960: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3961: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
3962: DMGetDS(dm, &prob);
3963: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3964: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3965: if (dmAux) {
3966: DMGetLocalSection(dmAux, §ionAux);
3967: DMGetDS(dmAux, &probAux);
3968: }
3969: /* Get flags */
3970: PetscDSGetNumFields(prob, &Nf);
3971: DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3972: for (fieldI = 0; fieldI < Nf; ++fieldI) {
3973: PetscObject disc;
3974: PetscClassId id;
3975: PetscDSGetDiscretization(prob, fieldI, &disc);
3976: PetscObjectGetClassId(disc, &id);
3977: if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;}
3978: else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
3979: }
3980: PetscDSHasJacobian(prob, &hasJac);
3981: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
3982: PetscDSHasDynamicJacobian(prob, &hasDyn);
3983: assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
3984: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
3985: PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);
3986: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
3987: /* Setup input data and temp arrays (should be DMGetWorkArray) */
3988: if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
3989: if (isMatIS) {MatISGetLocalMat(Jac, &J);}
3990: if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
3991: if (hasFV) {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
3992: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3993: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3994: PetscDSGetTotalDimension(prob, &totDim);
3995: if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
3996: CHKMEMQ;
3997: /* Compute batch sizes */
3998: if (isFE[0]) {
3999: PetscFE fe;
4000: PetscQuadrature q;
4001: PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4003: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4004: PetscFEGetQuadrature(fe, &q);
4005: PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
4006: PetscFEGetDimension(fe, &Nb);
4007: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4008: blockSize = Nb*numQuadPoints;
4009: batchSize = numBlocks * blockSize;
4010: chunkSize = numBatches * batchSize;
4011: numChunks = numCells / chunkSize + numCells % chunkSize;
4012: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4013: } else {
4014: chunkSize = numCells;
4015: numChunks = 1;
4016: }
4017: /* Get work space */
4018: wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
4019: DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
4020: PetscArrayzero(work, wsz);
4021: off = 0;
4022: u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
4023: u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
4024: a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL;
4025: elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4026: elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4027: elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4028: if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
4029: /* Setup geometry */
4030: DMGetCoordinateField(dm, &coordField);
4031: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4032: if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
4033: if (!qGeom) {
4034: PetscFE fe;
4036: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4037: PetscFEGetQuadrature(fe, &qGeom);
4038: PetscObjectReference((PetscObject) qGeom);
4039: }
4040: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4041: /* Compute volume integrals */
4042: if (assembleJac) {MatZeroEntries(J);}
4043: MatZeroEntries(JP);
4044: for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4045: const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4046: PetscInt c;
4048: /* Extract values */
4049: for (c = 0; c < Ncell; ++c) {
4050: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4051: PetscScalar *x = NULL, *x_t = NULL;
4052: PetscInt i;
4054: if (X) {
4055: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
4056: for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
4057: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
4058: }
4059: if (X_t) {
4060: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
4061: for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
4062: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
4063: }
4064: if (dmAux) {
4065: DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
4066: for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
4067: DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
4068: }
4069: }
4070: CHKMEMQ;
4071: for (fieldI = 0; fieldI < Nf; ++fieldI) {
4072: PetscFE fe;
4073: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
4074: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
4075: if (hasJac) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
4076: if (hasPrec) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
4077: if (hasDyn) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
4078: }
4079: /* For finite volume, add the identity */
4080: if (!isFE[fieldI]) {
4081: PetscFV fv;
4082: PetscInt eOffset = 0, Nc, fc, foff;
4084: PetscDSGetFieldOffset(prob, fieldI, &foff);
4085: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
4086: PetscFVGetNumComponents(fv, &Nc);
4087: for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
4088: for (fc = 0; fc < Nc; ++fc) {
4089: const PetscInt i = foff + fc;
4090: if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;}
4091: if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
4092: }
4093: }
4094: }
4095: }
4096: CHKMEMQ;
4097: /* Add contribution from X_t */
4098: if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
4099: /* Insert values into matrix */
4100: for (c = 0; c < Ncell; ++c) {
4101: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4102: if (mesh->printFEM > 1) {
4103: if (hasJac) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
4104: if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
4105: }
4106: if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
4107: DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
4108: }
4109: CHKMEMQ;
4110: }
4111: /* Cleanup */
4112: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4113: PetscQuadratureDestroy(&qGeom);
4114: if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
4115: DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4116: 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);
4117: /* Compute boundary integrals */
4118: /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
4119: /* Assemble matrix */
4120: if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
4121: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
4122: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
4123: CHKMEMQ;
4124: return(0);
4125: }
4127: /******** FEM Assembly Function ********/
4129: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4130: {
4131: PetscBool isPlex;
4135: PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
4136: if (isPlex) {
4137: *plex = dm;
4138: PetscObjectReference((PetscObject) dm);
4139: } else {
4140: PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
4141: if (!*plex) {
4142: DMConvert(dm,DMPLEX,plex);
4143: PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
4144: if (copy) {
4145: const char *comps[] = {"A", "dmAux"};
4146: PetscObject obj;
4147: PetscInt i;
4149: for (i = 0; i < 2; ++i) {
4150: PetscObjectQuery((PetscObject) dm, comps[i], &obj);
4151: PetscObjectCompose((PetscObject) *plex, comps[i], obj);
4152: }
4153: }
4154: } else {
4155: PetscObjectReference((PetscObject) *plex);
4156: }
4157: }
4158: return(0);
4159: }
4161: /*@
4162: DMPlexGetGeometryFVM - Return precomputed geometric data
4164: Collective on DM
4166: Input Parameter:
4167: . dm - The DM
4169: Output Parameters:
4170: + facegeom - The values precomputed from face geometry
4171: . cellgeom - The values precomputed from cell geometry
4172: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell
4174: Level: developer
4176: .seealso: DMPlexTSSetRHSFunctionLocal()
4177: @*/
4178: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4179: {
4180: DM plex;
4185: DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4186: DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4187: if (minRadius) {DMPlexGetMinRadius(plex, minRadius);}
4188: DMDestroy(&plex);
4189: return(0);
4190: }
4192: /*@
4193: DMPlexGetGradientDM - Return gradient data layout
4195: Collective on DM
4197: Input Parameters:
4198: + dm - The DM
4199: - fv - The PetscFV
4201: Output Parameter:
4202: . dmGrad - The layout for gradient values
4204: Level: developer
4206: .seealso: DMPlexSNESGetGeometryFVM()
4207: @*/
4208: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4209: {
4210: DM plex;
4211: PetscBool computeGradients;
4218: PetscFVGetComputeGradients(fv, &computeGradients);
4219: if (!computeGradients) {*dmGrad = NULL; return(0);}
4220: DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4221: DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4222: DMDestroy(&plex);
4223: return(0);
4224: }
4226: static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4227: {
4228: DM_Plex *mesh = (DM_Plex *) dm->data;
4229: DM plex = NULL, plexA = NULL;
4230: DMEnclosureType encAux;
4231: PetscDS prob, probAux = NULL;
4232: PetscSection section, sectionAux = NULL;
4233: Vec locA = NULL;
4234: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4235: PetscInt v;
4236: PetscInt totDim, totDimAux = 0;
4237: PetscErrorCode ierr;
4240: DMConvert(dm, DMPLEX, &plex);
4241: DMGetLocalSection(dm, §ion);
4242: DMGetDS(dm, &prob);
4243: PetscDSGetTotalDimension(prob, &totDim);
4244: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4245: if (locA) {
4246: DM dmAux;
4248: VecGetDM(locA, &dmAux);
4249: DMGetEnclosureRelation(dmAux, dm, &encAux);
4250: DMConvert(dmAux, DMPLEX, &plexA);
4251: DMGetDS(plexA, &probAux);
4252: PetscDSGetTotalDimension(probAux, &totDimAux);
4253: DMGetLocalSection(plexA, §ionAux);
4254: }
4255: for (v = 0; v < numValues; ++v) {
4256: PetscFEGeom *fgeom;
4257: PetscInt maxDegree;
4258: PetscQuadrature qGeom = NULL;
4259: IS pointIS;
4260: const PetscInt *points;
4261: PetscInt numFaces, face, Nq;
4263: DMLabelGetStratumIS(label, values[v], &pointIS);
4264: if (!pointIS) continue; /* No points with that id on this process */
4265: {
4266: IS isectIS;
4268: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
4269: ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4270: ISDestroy(&pointIS);
4271: pointIS = isectIS;
4272: }
4273: ISGetLocalSize(pointIS,&numFaces);
4274: ISGetIndices(pointIS,&points);
4275: PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a);
4276: DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4277: if (maxDegree <= 1) {
4278: DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4279: }
4280: if (!qGeom) {
4281: PetscFE fe;
4283: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4284: PetscFEGetFaceQuadrature(fe, &qGeom);
4285: PetscObjectReference((PetscObject)qGeom);
4286: }
4287: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
4288: DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4289: for (face = 0; face < numFaces; ++face) {
4290: const PetscInt point = points[face], *support, *cone;
4291: PetscScalar *x = NULL;
4292: PetscInt i, coneSize, faceLoc;
4294: DMPlexGetSupport(dm, point, &support);
4295: DMPlexGetConeSize(dm, support[0], &coneSize);
4296: DMPlexGetCone(dm, support[0], &cone);
4297: for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
4298: if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]);
4299: fgeom->face[face][0] = faceLoc;
4300: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
4301: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
4302: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
4303: if (locX_t) {
4304: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
4305: for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
4306: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
4307: }
4308: if (locA) {
4309: PetscInt subp;
4311: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
4312: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
4313: for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
4314: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
4315: }
4316: }
4317: PetscArrayzero(elemVec, numFaces*totDim);
4318: {
4319: PetscFE fe;
4320: PetscInt Nb;
4321: PetscFEGeom *chunkGeom = NULL;
4322: /* Conforming batches */
4323: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
4324: /* Remainder */
4325: PetscInt Nr, offset;
4327: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4328: PetscFEGetDimension(fe, &Nb);
4329: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4330: /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
4331: blockSize = Nb;
4332: batchSize = numBlocks * blockSize;
4333: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4334: numChunks = numFaces / (numBatches*batchSize);
4335: Ne = numChunks*numBatches*batchSize;
4336: Nr = numFaces % (numBatches*batchSize);
4337: offset = numFaces - Nr;
4338: PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
4339: PetscFEIntegrateBdResidual(prob, field, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4340: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
4341: PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
4342: PetscFEIntegrateBdResidual(prob, field, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, a ? &a[offset*totDimAux] : NULL, t, &elemVec[offset*totDim]);
4343: PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
4344: }
4345: for (face = 0; face < numFaces; ++face) {
4346: const PetscInt point = points[face], *support;
4348: if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim]);}
4349: DMPlexGetSupport(plex, point, &support);
4350: DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES);
4351: }
4352: DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4353: PetscQuadratureDestroy(&qGeom);
4354: ISRestoreIndices(pointIS, &points);
4355: ISDestroy(&pointIS);
4356: PetscFree4(u, u_t, elemVec, a);
4357: }
4358: DMDestroy(&plex);
4359: DMDestroy(&plexA);
4360: return(0);
4361: }
4363: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF)
4364: {
4365: DMField coordField;
4366: DMLabel depthLabel;
4367: IS facetIS;
4368: PetscInt dim;
4372: DMGetDimension(dm, &dim);
4373: DMPlexGetDepthLabel(dm, &depthLabel);
4374: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
4375: DMGetCoordinateField(dm, &coordField);
4376: DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4377: ISDestroy(&facetIS);
4378: return(0);
4379: }
4381: PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4382: {
4383: PetscDS prob;
4384: PetscInt numBd, bd;
4385: DMField coordField = NULL;
4386: IS facetIS = NULL;
4387: DMLabel depthLabel;
4388: PetscInt dim;
4392: DMGetDS(dm, &prob);
4393: DMPlexGetDepthLabel(dm, &depthLabel);
4394: DMGetDimension(dm, &dim);
4395: DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS);
4396: PetscDSGetNumBoundary(prob, &numBd);
4397: for (bd = 0; bd < numBd; ++bd) {
4398: DMBoundaryConditionType type;
4399: const char *bdLabel;
4400: DMLabel label;
4401: const PetscInt *values;
4402: PetscInt field, numValues;
4403: PetscObject obj;
4404: PetscClassId id;
4406: PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &field, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
4407: PetscDSGetDiscretization(prob, field, &obj);
4408: PetscObjectGetClassId(obj, &id);
4409: if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
4410: if (!facetIS) {
4411: DMLabel depthLabel;
4412: PetscInt dim;
4414: DMPlexGetDepthLabel(dm, &depthLabel);
4415: DMGetDimension(dm, &dim);
4416: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4417: }
4418: DMGetCoordinateField(dm, &coordField);
4419: DMGetLabel(dm, bdLabel, &label);
4420: DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4421: }
4422: ISDestroy(&facetIS);
4423: return(0);
4424: }
4426: PetscErrorCode DMPlexComputeResidual_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4427: {
4428: DM_Plex *mesh = (DM_Plex *) dm->data;
4429: const char *name = "Residual";
4430: DM dmAux = NULL;
4431: DM dmGrad = NULL;
4432: DMLabel ghostLabel = NULL;
4433: PetscDS prob = NULL;
4434: PetscDS probAux = NULL;
4435: PetscSection section = NULL;
4436: PetscBool useFEM = PETSC_FALSE;
4437: PetscBool useFVM = PETSC_FALSE;
4438: PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
4439: PetscFV fvm = NULL;
4440: PetscFVCellGeom *cgeomFVM = NULL;
4441: PetscFVFaceGeom *fgeomFVM = NULL;
4442: DMField coordField = NULL;
4443: Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
4444: PetscScalar *u = NULL, *u_t, *a, *uL, *uR;
4445: IS chunkIS;
4446: const PetscInt *cells;
4447: PetscInt cStart, cEnd, numCells;
4448: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
4449: PetscInt maxDegree = PETSC_MAX_INT;
4450: PetscQuadrature affineQuad = NULL, *quads = NULL;
4451: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4452: PetscErrorCode ierr;
4455: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4456: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4457: /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
4458: /* FEM+FVM */
4459: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4460: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4461: /* 1: Get sizes from dm and dmAux */
4462: DMGetLocalSection(dm, §ion);
4463: DMGetLabel(dm, "ghost", &ghostLabel);
4464: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
4465: PetscDSGetNumFields(prob, &Nf);
4466: PetscDSGetTotalDimension(prob, &totDim);
4467: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4468: if (locA) {
4469: PetscInt subcell;
4470: VecGetDM(locA, &dmAux);
4471: DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell);
4472: DMGetCellDS(dmAux, subcell, &probAux);
4473: PetscDSGetTotalDimension(probAux, &totDimAux);
4474: }
4475: /* 2: Get geometric data */
4476: for (f = 0; f < Nf; ++f) {
4477: PetscObject obj;
4478: PetscClassId id;
4479: PetscBool fimp;
4481: PetscDSGetImplicit(prob, f, &fimp);
4482: if (isImplicit != fimp) continue;
4483: PetscDSGetDiscretization(prob, f, &obj);
4484: PetscObjectGetClassId(obj, &id);
4485: if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
4486: if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;}
4487: }
4488: if (useFEM) {
4489: DMGetCoordinateField(dm, &coordField);
4490: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
4491: if (maxDegree <= 1) {
4492: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
4493: if (affineQuad) {
4494: DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4495: }
4496: } else {
4497: PetscCalloc2(Nf,&quads,Nf,&geoms);
4498: for (f = 0; f < Nf; ++f) {
4499: PetscObject obj;
4500: PetscClassId id;
4501: PetscBool fimp;
4503: PetscDSGetImplicit(prob, f, &fimp);
4504: if (isImplicit != fimp) continue;
4505: PetscDSGetDiscretization(prob, f, &obj);
4506: PetscObjectGetClassId(obj, &id);
4507: if (id == PETSCFE_CLASSID) {
4508: PetscFE fe = (PetscFE) obj;
4510: PetscFEGetQuadrature(fe, &quads[f]);
4511: PetscObjectReference((PetscObject)quads[f]);
4512: DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4513: }
4514: }
4515: }
4516: }
4517: if (useFVM) {
4518: DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);
4519: VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM);
4520: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
4521: /* Reconstruct and limit cell gradients */
4522: DMPlexGetGradientDM(dm, fvm, &dmGrad);
4523: if (dmGrad) {
4524: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4525: DMGetGlobalVector(dmGrad, &grad);
4526: DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
4527: /* Communicate gradient values */
4528: DMGetLocalVector(dmGrad, &locGrad);
4529: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
4530: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
4531: DMRestoreGlobalVector(dmGrad, &grad);
4532: }
4533: /* Handle non-essential (e.g. outflow) boundary values */
4534: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);
4535: }
4536: /* Loop over chunks */
4537: if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
4538: numCells = cEnd - cStart;
4539: numChunks = 1;
4540: cellChunkSize = numCells/numChunks;
4541: faceChunkSize = (fEnd - fStart)/numChunks;
4542: numChunks = PetscMin(1,numCells);
4543: for (chunk = 0; chunk < numChunks; ++chunk) {
4544: PetscScalar *elemVec, *fluxL, *fluxR;
4545: PetscReal *vol;
4546: PetscFVFaceGeom *fgeom;
4547: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4548: PetscInt fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face;
4550: /* Extract field coefficients */
4551: if (useFEM) {
4552: ISGetPointSubrange(chunkIS, cS, cE, cells);
4553: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4554: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4555: PetscArrayzero(elemVec, numCells*totDim);
4556: }
4557: if (useFVM) {
4558: DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4559: DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4560: DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4561: DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4562: PetscArrayzero(fluxL, numFaces*totDim);
4563: PetscArrayzero(fluxR, numFaces*totDim);
4564: }
4565: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
4566: /* Loop over fields */
4567: for (f = 0; f < Nf; ++f) {
4568: PetscObject obj;
4569: PetscClassId id;
4570: PetscBool fimp;
4571: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
4573: PetscDSGetImplicit(prob, f, &fimp);
4574: if (isImplicit != fimp) continue;
4575: PetscDSGetDiscretization(prob, f, &obj);
4576: PetscObjectGetClassId(obj, &id);
4577: if (id == PETSCFE_CLASSID) {
4578: PetscFE fe = (PetscFE) obj;
4579: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4580: PetscFEGeom *chunkGeom = NULL;
4581: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4582: PetscInt Nq, Nb;
4584: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4585: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4586: PetscFEGetDimension(fe, &Nb);
4587: blockSize = Nb;
4588: batchSize = numBlocks * blockSize;
4589: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4590: numChunks = numCells / (numBatches*batchSize);
4591: Ne = numChunks*numBatches*batchSize;
4592: Nr = numCells % (numBatches*batchSize);
4593: offset = numCells - Nr;
4594: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4595: /* 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) */
4596: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4597: PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4598: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4599: PetscFEIntegrateResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4600: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4601: } else if (id == PETSCFV_CLASSID) {
4602: PetscFV fv = (PetscFV) obj;
4604: Ne = numFaces;
4605: /* Riemann solve over faces (need fields at face centroids) */
4606: /* We need to evaluate FE fields at those coordinates */
4607: PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4608: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
4609: }
4610: /* Loop over domain */
4611: if (useFEM) {
4612: /* Add elemVec to locX */
4613: for (c = cS; c < cE; ++c) {
4614: const PetscInt cell = cells ? cells[c] : c;
4615: const PetscInt cind = c - cStart;
4617: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
4618: if (ghostLabel) {
4619: PetscInt ghostVal;
4621: DMLabelGetValue(ghostLabel,cell,&ghostVal);
4622: if (ghostVal > 0) continue;
4623: }
4624: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4625: }
4626: }
4627: if (useFVM) {
4628: PetscScalar *fa;
4629: PetscInt iface;
4631: VecGetArray(locF, &fa);
4632: for (f = 0; f < Nf; ++f) {
4633: PetscFV fv;
4634: PetscObject obj;
4635: PetscClassId id;
4636: PetscInt foff, pdim;
4638: PetscDSGetDiscretization(prob, f, &obj);
4639: PetscDSGetFieldOffset(prob, f, &foff);
4640: PetscObjectGetClassId(obj, &id);
4641: if (id != PETSCFV_CLASSID) continue;
4642: fv = (PetscFV) obj;
4643: PetscFVGetNumComponents(fv, &pdim);
4644: /* Accumulate fluxes to cells */
4645: for (face = fS, iface = 0; face < fE; ++face) {
4646: const PetscInt *scells;
4647: PetscScalar *fL = NULL, *fR = NULL;
4648: PetscInt ghost, d, nsupp, nchild;
4650: DMLabelGetValue(ghostLabel, face, &ghost);
4651: DMPlexGetSupportSize(dm, face, &nsupp);
4652: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4653: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4654: DMPlexGetSupport(dm, face, &scells);
4655: DMLabelGetValue(ghostLabel,scells[0],&ghost);
4656: if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);}
4657: DMLabelGetValue(ghostLabel,scells[1],&ghost);
4658: if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);}
4659: for (d = 0; d < pdim; ++d) {
4660: if (fL) fL[d] -= fluxL[iface*totDim+foff+d];
4661: if (fR) fR[d] += fluxR[iface*totDim+foff+d];
4662: }
4663: ++iface;
4664: }
4665: }
4666: VecRestoreArray(locF, &fa);
4667: }
4668: /* Handle time derivative */
4669: if (locX_t) {
4670: PetscScalar *x_t, *fa;
4672: VecGetArray(locF, &fa);
4673: VecGetArray(locX_t, &x_t);
4674: for (f = 0; f < Nf; ++f) {
4675: PetscFV fv;
4676: PetscObject obj;
4677: PetscClassId id;
4678: PetscInt pdim, d;
4680: PetscDSGetDiscretization(prob, f, &obj);
4681: PetscObjectGetClassId(obj, &id);
4682: if (id != PETSCFV_CLASSID) continue;
4683: fv = (PetscFV) obj;
4684: PetscFVGetNumComponents(fv, &pdim);
4685: for (c = cS; c < cE; ++c) {
4686: const PetscInt cell = cells ? cells[c] : c;
4687: PetscScalar *u_t, *r;
4689: if (ghostLabel) {
4690: PetscInt ghostVal;
4692: DMLabelGetValue(ghostLabel, cell, &ghostVal);
4693: if (ghostVal > 0) continue;
4694: }
4695: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4696: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4697: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4698: }
4699: }
4700: VecRestoreArray(locX_t, &x_t);
4701: VecRestoreArray(locF, &fa);
4702: }
4703: if (useFEM) {
4704: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4705: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4706: }
4707: if (useFVM) {
4708: DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4709: DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4710: DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4711: DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4712: if (dmGrad) {DMRestoreLocalVector(dmGrad, &locGrad);}
4713: }
4714: }
4715: if (useFEM) {ISDestroy(&chunkIS);}
4716: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
4718: if (useFEM) {
4719: DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);
4721: if (maxDegree <= 1) {
4722: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4723: PetscQuadratureDestroy(&affineQuad);
4724: } else {
4725: for (f = 0; f < Nf; ++f) {
4726: DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4727: PetscQuadratureDestroy(&quads[f]);
4728: }
4729: PetscFree2(quads,geoms);
4730: }
4731: }
4733: /* FEM */
4734: /* 1: Get sizes from dm and dmAux */
4735: /* 2: Get geometric data */
4736: /* 3: Handle boundary values */
4737: /* 4: Loop over domain */
4738: /* Extract coefficients */
4739: /* Loop over fields */
4740: /* Set tiling for FE*/
4741: /* Integrate FE residual to get elemVec */
4742: /* Loop over subdomain */
4743: /* Loop over quad points */
4744: /* Transform coords to real space */
4745: /* Evaluate field and aux fields at point */
4746: /* Evaluate residual at point */
4747: /* Transform residual to real space */
4748: /* Add residual to elemVec */
4749: /* Loop over domain */
4750: /* Add elemVec to locX */
4752: /* FVM */
4753: /* Get geometric data */
4754: /* If using gradients */
4755: /* Compute gradient data */
4756: /* Loop over domain faces */
4757: /* Count computational faces */
4758: /* Reconstruct cell gradient */
4759: /* Loop over domain cells */
4760: /* Limit cell gradients */
4761: /* Handle boundary values */
4762: /* Loop over domain faces */
4763: /* Read out field, centroid, normal, volume for each side of face */
4764: /* Riemann solve over faces */
4765: /* Loop over domain faces */
4766: /* Accumulate fluxes to cells */
4767: /* TODO Change printFEM to printDisc here */
4768: if (mesh->printFEM) {
4769: Vec locFbc;
4770: PetscInt pStart, pEnd, p, maxDof;
4771: PetscScalar *zeroes;
4773: VecDuplicate(locF,&locFbc);
4774: VecCopy(locF,locFbc);
4775: PetscSectionGetChart(section,&pStart,&pEnd);
4776: PetscSectionGetMaxDof(section,&maxDof);
4777: PetscCalloc1(maxDof,&zeroes);
4778: for (p = pStart; p < pEnd; p++) {
4779: VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);
4780: }
4781: PetscFree(zeroes);
4782: DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4783: VecDestroy(&locFbc);
4784: }
4785: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4786: return(0);
4787: }
4789: PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4790: {
4791: DM_Plex *mesh = (DM_Plex *) dm->data;
4792: const char *name = "Hybrid Residual";
4793: DM dmAux = NULL;
4794: DMLabel ghostLabel = NULL;
4795: PetscDS prob = NULL;
4796: PetscDS probAux = NULL;
4797: PetscSection section = NULL;
4798: DMField coordField = NULL;
4799: Vec locA;
4800: PetscScalar *u = NULL, *u_t, *a;
4801: PetscScalar *elemVec;
4802: IS chunkIS;
4803: const PetscInt *cells;
4804: PetscInt *faces;
4805: PetscInt cStart, cEnd, numCells;
4806: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk;
4807: PetscInt maxDegree = PETSC_MAX_INT;
4808: PetscQuadrature affineQuad = NULL, *quads = NULL;
4809: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4810: PetscErrorCode ierr;
4813: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4814: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4815: /* FEM */
4816: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4817: /* 1: Get sizes from dm and dmAux */
4818: DMGetSection(dm, §ion);
4819: DMGetLabel(dm, "ghost", &ghostLabel);
4820: DMGetCellDS(dm, cStart, &prob);
4821: PetscDSGetNumFields(prob, &Nf);
4822: PetscDSGetTotalDimension(prob, &totDim);
4823: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4824: if (locA) {
4825: VecGetDM(locA, &dmAux);
4826: DMGetCellDS(dmAux, cStart, &probAux);
4827: PetscDSGetTotalDimension(probAux, &totDimAux);
4828: }
4829: /* 2: Setup geometric data */
4830: DMGetCoordinateField(dm, &coordField);
4831: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4832: if (maxDegree > 1) {
4833: PetscCalloc2(Nf,&quads,Nf,&geoms);
4834: for (f = 0; f < Nf; ++f) {
4835: PetscFE fe;
4837: PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
4838: if (fe) {
4839: PetscFEGetQuadrature(fe, &quads[f]);
4840: PetscObjectReference((PetscObject) quads[f]);
4841: }
4842: }
4843: }
4844: /* Loop over chunks */
4845: numCells = cEnd - cStart;
4846: cellChunkSize = numCells;
4847: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
4848: PetscCalloc1(2*cellChunkSize, &faces);
4849: ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4850: /* Extract field coefficients */
4851: /* NOTE This needs the end cap faces to have identical orientations */
4852: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
4853: DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);
4854: for (chunk = 0; chunk < numChunks; ++chunk) {
4855: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4857: PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));
4858: /* Get faces */
4859: for (c = cS; c < cE; ++c) {
4860: const PetscInt cell = cells ? cells[c] : c;
4861: const PetscInt *cone;
4862: DMPlexGetCone(dm, cell, &cone);
4863: faces[(c-cS)*2+0] = cone[0];
4864: faces[(c-cS)*2+1] = cone[1];
4865: }
4866: ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
4867: /* Get geometric data */
4868: if (maxDegree <= 1) {
4869: if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
4870: if (affineQuad) {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
4871: } else {
4872: for (f = 0; f < Nf; ++f) {
4873: if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
4874: }
4875: }
4876: /* Loop over fields */
4877: for (f = 0; f < Nf; ++f) {
4878: PetscFE fe;
4879: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4880: PetscFEGeom *chunkGeom = NULL;
4881: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4882: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
4884: PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
4885: if (!fe) continue;
4886: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4887: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4888: PetscFEGetDimension(fe, &Nb);
4889: blockSize = Nb;
4890: batchSize = numBlocks * blockSize;
4891: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4892: numChunks = numCells / (numBatches*batchSize);
4893: Ne = numChunks*numBatches*batchSize;
4894: Nr = numCells % (numBatches*batchSize);
4895: offset = numCells - Nr;
4896: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4897: PetscFEIntegrateHybridResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4898: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4899: PetscFEIntegrateHybridResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4900: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4901: }
4902: /* Add elemVec to locX */
4903: for (c = cS; c < cE; ++c) {
4904: const PetscInt cell = cells ? cells[c] : c;
4905: const PetscInt cind = c - cStart;
4907: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
4908: if (ghostLabel) {
4909: PetscInt ghostVal;
4911: DMLabelGetValue(ghostLabel,cell,&ghostVal);
4912: if (ghostVal > 0) continue;
4913: }
4914: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4915: }
4916: }
4917: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
4918: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4919: PetscFree(faces);
4920: ISDestroy(&chunkIS);
4921: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
4922: if (maxDegree <= 1) {
4923: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4924: PetscQuadratureDestroy(&affineQuad);
4925: } else {
4926: for (f = 0; f < Nf; ++f) {
4927: if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);}
4928: if (quads) {PetscQuadratureDestroy(&quads[f]);}
4929: }
4930: PetscFree2(quads,geoms);
4931: }
4932: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4933: return(0);
4934: }
4936: PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, 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)
4937: {
4938: DM_Plex *mesh = (DM_Plex *) dm->data;
4939: DM plex = NULL, plexA = NULL, tdm;
4940: DMEnclosureType encAux;
4941: PetscDS prob, probAux = NULL;
4942: PetscSection section, sectionAux = NULL;
4943: PetscSection globalSection, subSection = NULL;
4944: Vec locA = NULL, tv;
4945: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
4946: PetscInt v;
4947: PetscInt Nf, totDim, totDimAux = 0;
4948: PetscBool isMatISP, transform;
4949: PetscErrorCode ierr;
4952: DMConvert(dm, DMPLEX, &plex);
4953: DMHasBasisTransform(dm, &transform);
4954: DMGetBasisTransformDM_Internal(dm, &tdm);
4955: DMGetBasisTransformVec_Internal(dm, &tv);
4956: DMGetLocalSection(dm, §ion);
4957: DMGetDS(dm, &prob);
4958: PetscDSGetNumFields(prob, &Nf);
4959: PetscDSGetTotalDimension(prob, &totDim);
4960: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4961: if (locA) {
4962: DM dmAux;
4964: VecGetDM(locA, &dmAux);
4965: DMGetEnclosureRelation(dmAux, dm, &encAux);
4966: DMConvert(dmAux, DMPLEX, &plexA);
4967: DMGetDS(plexA, &probAux);
4968: PetscDSGetTotalDimension(probAux, &totDimAux);
4969: DMGetLocalSection(plexA, §ionAux);
4970: }
4972: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
4973: DMGetGlobalSection(dm, &globalSection);
4974: if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
4975: for (v = 0; v < numValues; ++v) {
4976: PetscFEGeom *fgeom;
4977: PetscInt maxDegree;
4978: PetscQuadrature qGeom = NULL;
4979: IS pointIS;
4980: const PetscInt *points;
4981: PetscInt numFaces, face, Nq;
4983: DMLabelGetStratumIS(label, values[v], &pointIS);
4984: if (!pointIS) continue; /* No points with that id on this process */
4985: {
4986: IS isectIS;
4988: /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
4989: ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4990: ISDestroy(&pointIS);
4991: pointIS = isectIS;
4992: }
4993: ISGetLocalSize(pointIS, &numFaces);
4994: ISGetIndices(pointIS, &points);
4995: PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);
4996: DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4997: if (maxDegree <= 1) {
4998: DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4999: }
5000: if (!qGeom) {
5001: PetscFE fe;
5003: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5004: PetscFEGetFaceQuadrature(fe, &qGeom);
5005: PetscObjectReference((PetscObject)qGeom);
5006: }
5007: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5008: DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5009: for (face = 0; face < numFaces; ++face) {
5010: const PetscInt point = points[face], *support, *cone;
5011: PetscScalar *x = NULL;
5012: PetscInt i, coneSize, faceLoc;
5014: DMPlexGetSupport(dm, point, &support);
5015: DMPlexGetConeSize(dm, support[0], &coneSize);
5016: DMPlexGetCone(dm, support[0], &cone);
5017: for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
5018: if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]);
5019: fgeom->face[face][0] = faceLoc;
5020: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5021: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
5022: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5023: if (locX_t) {
5024: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5025: for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
5026: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5027: }
5028: if (locA) {
5029: PetscInt subp;
5030: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5031: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5032: for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
5033: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5034: }
5035: }
5036: PetscArrayzero(elemMat, numFaces*totDim*totDim);
5037: {
5038: PetscFE fe;
5039: PetscInt Nb;
5040: /* Conforming batches */
5041: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5042: /* Remainder */
5043: PetscFEGeom *chunkGeom = NULL;
5044: PetscInt fieldJ, Nr, offset;
5046: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5047: PetscFEGetDimension(fe, &Nb);
5048: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5049: blockSize = Nb;
5050: batchSize = numBlocks * blockSize;
5051: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5052: numChunks = numFaces / (numBatches*batchSize);
5053: Ne = numChunks*numBatches*batchSize;
5054: Nr = numFaces % (numBatches*batchSize);
5055: offset = numFaces - Nr;
5056: PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
5057: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5058: PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5059: }
5060: PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
5061: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5062: PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, 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]);
5063: }
5064: PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
5065: }
5066: for (face = 0; face < numFaces; ++face) {
5067: const PetscInt point = points[face], *support;
5069: /* Transform to global basis before insertion in Jacobian */
5070: DMPlexGetSupport(plex, point, &support);
5071: if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);}
5072: if (mesh->printFEM > 1) {DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);}
5073: if (!isMatISP) {
5074: DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5075: } else {
5076: Mat lJ;
5078: MatISGetLocalMat(JacP, &lJ);
5079: DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5080: }
5081: }
5082: DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5083: PetscQuadratureDestroy(&qGeom);
5084: ISRestoreIndices(pointIS, &points);
5085: ISDestroy(&pointIS);
5086: PetscFree4(u, u_t, elemMat, a);
5087: }
5088: if (plex) {DMDestroy(&plex);}
5089: if (plexA) {DMDestroy(&plexA);}
5090: return(0);
5091: }
5093: PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP)
5094: {
5095: DMField coordField;
5096: DMLabel depthLabel;
5097: IS facetIS;
5098: PetscInt dim;
5102: DMGetDimension(dm, &dim);
5103: DMPlexGetDepthLabel(dm, &depthLabel);
5104: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5105: DMGetCoordinateField(dm, &coordField);
5106: DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5107: ISDestroy(&facetIS);
5108: return(0);
5109: }
5111: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5112: {
5113: PetscDS prob;
5114: PetscInt dim, numBd, bd;
5115: DMLabel depthLabel;
5116: DMField coordField = NULL;
5117: IS facetIS;
5118: PetscErrorCode ierr;
5121: DMGetDS(dm, &prob);
5122: DMPlexGetDepthLabel(dm, &depthLabel);
5123: DMGetDimension(dm, &dim);
5124: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5125: PetscDSGetNumBoundary(prob, &numBd);
5126: DMGetCoordinateField(dm, &coordField);
5127: for (bd = 0; bd < numBd; ++bd) {
5128: DMBoundaryConditionType type;
5129: const char *bdLabel;
5130: DMLabel label;
5131: const PetscInt *values;
5132: PetscInt fieldI, numValues;
5133: PetscObject obj;
5134: PetscClassId id;
5136: PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &fieldI, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
5137: PetscDSGetDiscretization(prob, fieldI, &obj);
5138: PetscObjectGetClassId(obj, &id);
5139: if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
5140: DMGetLabel(dm, bdLabel, &label);
5141: DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5142: }
5143: ISDestroy(&facetIS);
5144: return(0);
5145: }
5147: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user)
5148: {
5149: DM_Plex *mesh = (DM_Plex *) dm->data;
5150: const char *name = "Jacobian";
5151: DM dmAux, plex, tdm;
5152: DMEnclosureType encAux;
5153: Vec A, tv;
5154: DMField coordField;
5155: PetscDS prob, probAux = NULL;
5156: PetscSection section, globalSection, subSection, sectionAux;
5157: PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5158: const PetscInt *cells;
5159: PetscInt Nf, fieldI, fieldJ;
5160: PetscInt totDim, totDimAux, cStart, cEnd, numCells, c;
5161: PetscBool isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform;
5162: PetscErrorCode ierr;
5165: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5166: ISGetLocalSize(cellIS, &numCells);
5167: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5168: DMHasBasisTransform(dm, &transform);
5169: DMGetBasisTransformDM_Internal(dm, &tdm);
5170: DMGetBasisTransformVec_Internal(dm, &tv);
5171: DMGetLocalSection(dm, §ion);
5172: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5173: DMGetGlobalSection(dm, &globalSection);
5174: if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5175: ISGetLocalSize(cellIS, &numCells);
5176: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5177: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5178: PetscDSGetNumFields(prob, &Nf);
5179: PetscDSGetTotalDimension(prob, &totDim);
5180: PetscDSHasJacobian(prob, &hasJac);
5181: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
5182: /* user passed in the same matrix, avoid double contributions and
5183: only assemble the Jacobian */
5184: if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
5185: PetscDSHasDynamicJacobian(prob, &hasDyn);
5186: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5187: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
5188: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
5189: if (dmAux) {
5190: DMGetEnclosureRelation(dmAux, dm, &encAux);
5191: DMConvert(dmAux, DMPLEX, &plex);
5192: DMGetLocalSection(plex, §ionAux);
5193: DMGetDS(dmAux, &probAux);
5194: PetscDSGetTotalDimension(probAux, &totDimAux);
5195: }
5196: 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);
5197: if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
5198: DMGetCoordinateField(dm, &coordField);
5199: for (c = cStart; c < cEnd; ++c) {
5200: const PetscInt cell = cells ? cells[c] : c;
5201: const PetscInt cind = c - cStart;
5202: PetscScalar *x = NULL, *x_t = NULL;
5203: PetscInt i;
5205: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5206: for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5207: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5208: if (X_t) {
5209: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5210: for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5211: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5212: }
5213: if (dmAux) {
5214: PetscInt subcell;
5215: DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5216: DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5217: for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5218: DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5219: }
5220: }
5221: if (hasJac) {PetscArrayzero(elemMat, numCells*totDim*totDim);}
5222: if (hasPrec) {PetscArrayzero(elemMatP, numCells*totDim*totDim);}
5223: if (hasDyn) {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5224: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5225: PetscClassId id;
5226: PetscFE fe;
5227: PetscQuadrature qGeom = NULL;
5228: PetscInt Nb;
5229: /* Conforming batches */
5230: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5231: /* Remainder */
5232: PetscInt Nr, offset, Nq;
5233: PetscInt maxDegree;
5234: PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
5236: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5237: PetscObjectGetClassId((PetscObject) fe, &id);
5238: if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;}
5239: PetscFEGetDimension(fe, &Nb);
5240: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5241: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
5242: if (maxDegree <= 1) {
5243: DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);
5244: }
5245: if (!qGeom) {
5246: PetscFEGetQuadrature(fe,&qGeom);
5247: PetscObjectReference((PetscObject)qGeom);
5248: }
5249: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5250: DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5251: blockSize = Nb;
5252: batchSize = numBlocks * blockSize;
5253: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5254: numChunks = numCells / (numBatches*batchSize);
5255: Ne = numChunks*numBatches*batchSize;
5256: Nr = numCells % (numBatches*batchSize);
5257: offset = numCells - Nr;
5258: PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
5259: PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);
5260: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5261: if (hasJac) {
5262: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5263: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5264: }
5265: if (hasPrec) {
5266: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5267: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5268: }
5269: if (hasDyn) {
5270: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5271: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);
5272: }
5273: }
5274: PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);
5275: PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);
5276: DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5277: PetscQuadratureDestroy(&qGeom);
5278: }
5279: /* Add contribution from X_t */
5280: if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
5281: if (hasFV) {
5282: PetscClassId id;
5283: PetscFV fv;
5284: PetscInt offsetI, NcI, NbI = 1, fc, f;
5286: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5287: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
5288: PetscDSGetFieldOffset(prob, fieldI, &offsetI);
5289: PetscObjectGetClassId((PetscObject) fv, &id);
5290: if (id != PETSCFV_CLASSID) continue;
5291: /* Put in the identity */
5292: PetscFVGetNumComponents(fv, &NcI);
5293: for (c = cStart; c < cEnd; ++c) {
5294: const PetscInt cind = c - cStart;
5295: const PetscInt eOffset = cind*totDim*totDim;
5296: for (fc = 0; fc < NcI; ++fc) {
5297: for (f = 0; f < NbI; ++f) {
5298: const PetscInt i = offsetI + f*NcI+fc;
5299: if (hasPrec) {
5300: if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;}
5301: elemMatP[eOffset+i*totDim+i] = 1.0;
5302: } else {elemMat[eOffset+i*totDim+i] = 1.0;}
5303: }
5304: }
5305: }
5306: }
5307: /* No allocated space for FV stuff, so ignore the zero entries */
5308: MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);
5309: }
5310: /* Insert values into matrix */
5311: isMatIS = PETSC_FALSE;
5312: if (hasPrec && hasJac) {
5313: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);
5314: }
5315: if (isMatIS && !subSection) {
5316: DMPlexGetSubdomainSection(dm, &subSection);
5317: }
5318: for (c = cStart; c < cEnd; ++c) {
5319: const PetscInt cell = cells ? cells[c] : c;
5320: const PetscInt cind = c - cStart;
5322: /* Transform to global basis before insertion in Jacobian */
5323: if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);}
5324: if (hasPrec) {
5325: if (hasJac) {
5326: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5327: if (!isMatIS) {
5328: DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5329: } else {
5330: Mat lJ;
5332: MatISGetLocalMat(Jac,&lJ);
5333: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5334: }
5335: }
5336: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5337: if (!isMatISP) {
5338: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5339: } else {
5340: Mat lJ;
5342: MatISGetLocalMat(JacP,&lJ);
5343: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5344: }
5345: } else {
5346: if (hasJac) {
5347: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5348: if (!isMatISP) {
5349: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5350: } else {
5351: Mat lJ;
5353: MatISGetLocalMat(JacP,&lJ);
5354: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5355: }
5356: }
5357: }
5358: }
5359: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5360: if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
5361: PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);
5362: if (dmAux) {
5363: PetscFree(a);
5364: DMDestroy(&plex);
5365: }
5366: /* Compute boundary integrals */
5367: DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5368: /* Assemble matrix */
5369: if (hasJac && hasPrec) {
5370: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5371: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5372: }
5373: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5374: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5375: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5376: return(0);
5377: }
5379: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5380: {
5381: DM_Plex *mesh = (DM_Plex *) dm->data;
5382: const char *name = "Hybrid Jacobian";
5383: DM dmAux = NULL;
5384: DM plex = NULL;
5385: DM plexA = NULL;
5386: DMLabel ghostLabel = NULL;
5387: PetscDS prob = NULL;
5388: PetscDS probAux = NULL;
5389: PetscSection section = NULL;
5390: DMField coordField = NULL;
5391: Vec locA;
5392: PetscScalar *u = NULL, *u_t, *a = NULL;
5393: PetscScalar *elemMat, *elemMatP;
5394: PetscSection globalSection, subSection, sectionAux;
5395: IS chunkIS;
5396: const PetscInt *cells;
5397: PetscInt *faces;
5398: PetscInt cStart, cEnd, numCells;
5399: PetscInt Nf, fieldI, fieldJ, totDim, totDimAux, numChunks, cellChunkSize, chunk;
5400: PetscInt maxDegree = PETSC_MAX_INT;
5401: PetscQuadrature affineQuad = NULL, *quads = NULL;
5402: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
5403: PetscBool isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec;
5404: PetscErrorCode ierr;
5407: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5408: ISGetLocalSize(cellIS, &numCells);
5409: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5410: DMConvert(dm, DMPLEX, &plex);
5411: DMGetSection(dm, §ion);
5412: DMGetGlobalSection(dm, &globalSection);
5413: DMGetLabel(dm, "ghost", &ghostLabel);
5414: DMGetCellDS(dm, cStart, &prob);
5415: PetscDSGetNumFields(prob, &Nf);
5416: PetscDSGetTotalDimension(prob, &totDim);
5417: PetscDSHasBdJacobian(prob, &hasBdJac);
5418: PetscDSHasBdJacobianPreconditioner(prob, &hasBdPrec);
5419: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5420: if (isMatISP) {DMPlexGetSubdomainSection(plex, &subSection);}
5421: if (hasBdPrec && hasBdJac) {PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);}
5422: if (isMatIS && !subSection) {DMPlexGetSubdomainSection(plex, &subSection);}
5423: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
5424: if (locA) {
5425: VecGetDM(locA, &dmAux);
5426: DMConvert(dmAux, DMPLEX, &plexA);
5427: DMGetSection(dmAux, §ionAux);
5428: DMGetCellDS(dmAux, cStart, &probAux);
5429: PetscDSGetTotalDimension(probAux, &totDimAux);
5430: }
5431: DMGetCoordinateField(dm, &coordField);
5432: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5433: if (maxDegree > 1) {
5434: PetscInt f;
5435: PetscCalloc2(Nf,&quads,Nf,&geoms);
5436: for (f = 0; f < Nf; ++f) {
5437: PetscFE fe;
5439: PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
5440: if (fe) {
5441: PetscFEGetQuadrature(fe, &quads[f]);
5442: PetscObjectReference((PetscObject) quads[f]);
5443: }
5444: }
5445: }
5446: cellChunkSize = numCells;
5447: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
5448: PetscCalloc1(2*cellChunkSize, &faces);
5449: ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5450: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5451: DMGetWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5452: DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5453: for (chunk = 0; chunk < numChunks; ++chunk) {
5454: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
5456: if (hasBdJac) {PetscMemzero(elemMat, numCells*totDim*totDim * sizeof(PetscScalar));}
5457: if (hasBdPrec) {PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));}
5458: /* Get faces */
5459: for (c = cS; c < cE; ++c) {
5460: const PetscInt cell = cells ? cells[c] : c;
5461: const PetscInt *cone;
5462: DMPlexGetCone(plex, cell, &cone);
5463: faces[(c-cS)*2+0] = cone[0];
5464: faces[(c-cS)*2+1] = cone[1];
5465: }
5466: ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
5467: if (maxDegree <= 1) {
5468: if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
5469: if (affineQuad) {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
5470: } else {
5471: PetscInt f;
5472: for (f = 0; f < Nf; ++f) {
5473: if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
5474: }
5475: }
5477: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5478: PetscFE feI;
5479: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI];
5480: PetscFEGeom *chunkGeom = NULL, *remGeom = NULL;
5481: PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5482: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
5484: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &feI);
5485: if (!feI) continue;
5486: PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5487: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5488: PetscFEGetDimension(feI, &Nb);
5489: blockSize = Nb;
5490: batchSize = numBlocks * blockSize;
5491: PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5492: numChunks = numCells / (numBatches*batchSize);
5493: Ne = numChunks*numBatches*batchSize;
5494: Nr = numCells % (numBatches*batchSize);
5495: offset = numCells - Nr;
5496: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5497: PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
5498: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5499: PetscFE feJ;
5501: PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &feJ);
5502: if (!feJ) continue;
5503: if (hasBdJac) {
5504: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5505: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5506: }
5507: if (hasBdPrec) {
5508: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5509: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5510: }
5511: }
5512: PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5513: PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5514: }
5515: /* Insert values into matrix */
5516: for (c = cS; c < cE; ++c) {
5517: const PetscInt cell = cells ? cells[c] : c;
5518: const PetscInt cind = c - cS;
5520: if (hasBdPrec) {
5521: if (hasBdJac) {
5522: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5523: if (!isMatIS) {
5524: DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5525: } else {
5526: Mat lJ;
5528: MatISGetLocalMat(Jac,&lJ);
5529: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5530: }
5531: }
5532: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5533: if (!isMatISP) {
5534: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5535: } else {
5536: Mat lJ;
5538: MatISGetLocalMat(JacP,&lJ);
5539: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5540: }
5541: } else if (hasBdJac) {
5542: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5543: if (!isMatISP) {
5544: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5545: } else {
5546: Mat lJ;
5548: MatISGetLocalMat(JacP,&lJ);
5549: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5550: }
5551: }
5552: }
5553: }
5554: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5555: DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5556: DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5557: PetscFree(faces);
5558: ISDestroy(&chunkIS);
5559: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5560: if (maxDegree <= 1) {
5561: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5562: PetscQuadratureDestroy(&affineQuad);
5563: } else {
5564: PetscInt f;
5565: for (f = 0; f < Nf; ++f) {
5566: if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);}
5567: if (quads) {PetscQuadratureDestroy(&quads[f]);}
5568: }
5569: PetscFree2(quads,geoms);
5570: }
5571: if (dmAux) {DMDestroy(&plexA);}
5572: DMDestroy(&plex);
5573: /* Assemble matrix */
5574: if (hasBdJac && hasBdPrec) {
5575: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5576: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5577: }
5578: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5579: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5580: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5581: return(0);
5582: }