Actual source code: plexfem.c
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);
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);
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] = {0.0,0.0};
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] = {0.0,0.0,0.0};
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, 1, &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, 1, &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: DMPlexSNESComputeResidualFEM()
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: DMPlexSNESComputeResidualFEM()
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;
2244: PetscScalar *x = NULL;
2245: PetscInt i;
2247: DMPlexGetSupport(dm, point, &support);
2248: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
2249: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
2250: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
2251: if (locA) {
2252: PetscInt subp;
2253: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
2254: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
2255: for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
2256: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
2257: }
2258: }
2259: /* Get blocking */
2260: {
2261: PetscQuadrature q;
2262: PetscInt numBatches, batchSize, numBlocks, blockSize;
2263: PetscInt Nq, Nb;
2265: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
2266: PetscFEGetQuadrature(fe, &q);
2267: PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2268: PetscFEGetDimension(fe, &Nb);
2269: blockSize = Nb*Nq;
2270: batchSize = numBlocks * blockSize;
2271: chunkSize = numBatches*batchSize;
2272: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2273: numChunks = numFaces / chunkSize;
2274: Nr = numFaces % chunkSize;
2275: offset = numFaces - Nr;
2276: }
2277: /* Do integration for each field */
2278: for (chunk = 0; chunk < numChunks; ++chunk) {
2279: PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);
2280: PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
2281: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
2282: }
2283: PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
2284: PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);
2285: PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
2286: /* Cleanup data arrays */
2287: DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2288: PetscQuadratureDestroy(&qGeom);
2289: PetscFree2(u, a);
2290: ISRestoreIndices(pointIS, &points);
2291: }
2292: }
2293: if (plex) {DMDestroy(&plex);}
2294: if (plexA) {DMDestroy(&plexA);}
2295: return(0);
2296: }
2298: /*@
2299: DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
2301: Input Parameters:
2302: + dm - The mesh
2303: . X - Global input vector
2304: . label - The boundary DMLabel
2305: . numVals - The number of label values to use, or PETSC_DETERMINE for all values
2306: . vals - The label values to use, or PETSC_NULL for all values
2307: . func = The function to integrate along the boundary
2308: - user - The user context
2310: Output Parameter:
2311: . integral - Integral for each field
2313: Level: developer
2315: .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM()
2316: @*/
2317: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[],
2318: void (*func)(PetscInt, PetscInt, PetscInt,
2319: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2320: const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2321: PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
2322: PetscScalar *integral, void *user)
2323: {
2324: Vec locX;
2325: PetscSection section;
2326: DMLabel depthLabel;
2327: IS facetIS;
2328: PetscInt dim, Nf, f, v;
2337: PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2338: DMPlexGetDepthLabel(dm, &depthLabel);
2339: DMGetDimension(dm, &dim);
2340: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
2341: DMGetLocalSection(dm, §ion);
2342: PetscSectionGetNumFields(section, &Nf);
2343: /* Get local solution with boundary values */
2344: DMGetLocalVector(dm, &locX);
2345: DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
2346: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
2347: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
2348: /* Loop over label values */
2349: PetscArrayzero(integral, Nf);
2350: for (v = 0; v < numVals; ++v) {
2351: IS pointIS;
2352: PetscInt numFaces, face;
2353: PetscScalar *fintegral;
2355: DMLabelGetStratumIS(label, vals[v], &pointIS);
2356: if (!pointIS) continue; /* No points with that id on this process */
2357: {
2358: IS isectIS;
2360: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
2361: ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
2362: ISDestroy(&pointIS);
2363: pointIS = isectIS;
2364: }
2365: ISGetLocalSize(pointIS, &numFaces);
2366: PetscCalloc1(numFaces*Nf, &fintegral);
2367: DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
2368: /* Sum point contributions into integral */
2369: for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f];
2370: PetscFree(fintegral);
2371: ISDestroy(&pointIS);
2372: }
2373: DMRestoreLocalVector(dm, &locX);
2374: ISDestroy(&facetIS);
2375: PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2376: return(0);
2377: }
2379: /*@
2380: DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to a uniformly refined DM.
2382: Input Parameters:
2383: + dmc - The coarse mesh
2384: . dmf - The fine mesh
2385: . isRefined - Flag indicating regular refinement, rather than the same topology
2386: - user - The user context
2388: Output Parameter:
2389: . In - The interpolation matrix
2391: Level: developer
2393: .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2394: @*/
2395: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2396: {
2397: DM_Plex *mesh = (DM_Plex *) dmc->data;
2398: const char *name = "Interpolator";
2399: PetscFE *feRef;
2400: PetscFV *fvRef;
2401: PetscSection fsection, fglobalSection;
2402: PetscSection csection, cglobalSection;
2403: PetscScalar *elemMat;
2404: PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
2405: PetscInt cTotDim=0, rTotDim = 0;
2406: PetscErrorCode ierr;
2409: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2410: DMGetDimension(dmf, &dim);
2411: DMGetLocalSection(dmf, &fsection);
2412: DMGetGlobalSection(dmf, &fglobalSection);
2413: DMGetLocalSection(dmc, &csection);
2414: DMGetGlobalSection(dmc, &cglobalSection);
2415: PetscSectionGetNumFields(fsection, &Nf);
2416: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
2417: PetscCalloc2(Nf, &feRef, Nf, &fvRef);
2418: for (f = 0; f < Nf; ++f) {
2419: PetscObject obj, objc;
2420: PetscClassId id, idc;
2421: PetscInt rNb = 0, Nc = 0, cNb = 0;
2423: DMGetField(dmf, f, NULL, &obj);
2424: PetscObjectGetClassId(obj, &id);
2425: if (id == PETSCFE_CLASSID) {
2426: PetscFE fe = (PetscFE) obj;
2428: if (isRefined) {
2429: PetscFERefine(fe, &feRef[f]);
2430: } else {
2431: PetscObjectReference((PetscObject) fe);
2432: feRef[f] = fe;
2433: }
2434: PetscFEGetDimension(feRef[f], &rNb);
2435: PetscFEGetNumComponents(fe, &Nc);
2436: } else if (id == PETSCFV_CLASSID) {
2437: PetscFV fv = (PetscFV) obj;
2438: PetscDualSpace Q;
2440: if (isRefined) {
2441: PetscFVRefine(fv, &fvRef[f]);
2442: } else {
2443: PetscObjectReference((PetscObject) fv);
2444: fvRef[f] = fv;
2445: }
2446: PetscFVGetDualSpace(fvRef[f], &Q);
2447: PetscDualSpaceGetDimension(Q, &rNb);
2448: PetscFVGetDualSpace(fv, &Q);
2449: PetscFVGetNumComponents(fv, &Nc);
2450: }
2451: DMGetField(dmc, f, NULL, &objc);
2452: PetscObjectGetClassId(objc, &idc);
2453: if (idc == PETSCFE_CLASSID) {
2454: PetscFE fe = (PetscFE) objc;
2456: PetscFEGetDimension(fe, &cNb);
2457: } else if (id == PETSCFV_CLASSID) {
2458: PetscFV fv = (PetscFV) obj;
2459: PetscDualSpace Q;
2461: PetscFVGetDualSpace(fv, &Q);
2462: PetscDualSpaceGetDimension(Q, &cNb);
2463: }
2464: rTotDim += rNb;
2465: cTotDim += cNb;
2466: }
2467: PetscMalloc1(rTotDim*cTotDim,&elemMat);
2468: PetscArrayzero(elemMat, rTotDim*cTotDim);
2469: for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2470: PetscDualSpace Qref;
2471: PetscQuadrature f;
2472: const PetscReal *qpoints, *qweights;
2473: PetscReal *points;
2474: PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d;
2476: /* Compose points from all dual basis functionals */
2477: if (feRef[fieldI]) {
2478: PetscFEGetDualSpace(feRef[fieldI], &Qref);
2479: PetscFEGetNumComponents(feRef[fieldI], &Nc);
2480: } else {
2481: PetscFVGetDualSpace(fvRef[fieldI], &Qref);
2482: PetscFVGetNumComponents(fvRef[fieldI], &Nc);
2483: }
2484: PetscDualSpaceGetDimension(Qref, &fpdim);
2485: for (i = 0; i < fpdim; ++i) {
2486: PetscDualSpaceGetFunctional(Qref, i, &f);
2487: PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
2488: npoints += Np;
2489: }
2490: PetscMalloc1(npoints*dim,&points);
2491: for (i = 0, k = 0; i < fpdim; ++i) {
2492: PetscDualSpaceGetFunctional(Qref, i, &f);
2493: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2494: for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
2495: }
2497: for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
2498: PetscObject obj;
2499: PetscClassId id;
2500: PetscInt NcJ = 0, cpdim = 0, j, qNc;
2502: DMGetField(dmc, fieldJ, NULL, &obj);
2503: PetscObjectGetClassId(obj, &id);
2504: if (id == PETSCFE_CLASSID) {
2505: PetscFE fe = (PetscFE) obj;
2506: PetscTabulation T = NULL;
2508: /* Evaluate basis at points */
2509: PetscFEGetNumComponents(fe, &NcJ);
2510: PetscFEGetDimension(fe, &cpdim);
2511: /* For now, fields only interpolate themselves */
2512: if (fieldI == fieldJ) {
2513: 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);
2514: PetscFECreateTabulation(fe, 1, npoints, points, 0, &T);
2515: for (i = 0, k = 0; i < fpdim; ++i) {
2516: PetscDualSpaceGetFunctional(Qref, i, &f);
2517: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2518: 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);
2519: for (p = 0; p < Np; ++p, ++k) {
2520: for (j = 0; j < cpdim; ++j) {
2521: /*
2522: cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2523: offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields
2524: fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2525: qNC, Nc, Ncj, c: Number of components in this field
2526: Np, p: Number of quad points in the fine grid functional i
2527: k: i*Np + p, overall point number for the interpolation
2528: */
2529: 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];
2530: }
2531: }
2532: }
2533: PetscTabulationDestroy(&T);
2534: }
2535: } else if (id == PETSCFV_CLASSID) {
2536: PetscFV fv = (PetscFV) obj;
2538: /* Evaluate constant function at points */
2539: PetscFVGetNumComponents(fv, &NcJ);
2540: cpdim = 1;
2541: /* For now, fields only interpolate themselves */
2542: if (fieldI == fieldJ) {
2543: 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);
2544: for (i = 0, k = 0; i < fpdim; ++i) {
2545: PetscDualSpaceGetFunctional(Qref, i, &f);
2546: PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2547: 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);
2548: for (p = 0; p < Np; ++p, ++k) {
2549: for (j = 0; j < cpdim; ++j) {
2550: for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c];
2551: }
2552: }
2553: }
2554: }
2555: }
2556: offsetJ += cpdim;
2557: }
2558: offsetI += fpdim;
2559: PetscFree(points);
2560: }
2561: if (mesh->printFEM > 1) {DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);}
2562: /* Preallocate matrix */
2563: {
2564: Mat preallocator;
2565: PetscScalar *vals;
2566: PetscInt *cellCIndices, *cellFIndices;
2567: PetscInt locRows, locCols, cell;
2569: MatGetLocalSize(In, &locRows, &locCols);
2570: MatCreate(PetscObjectComm((PetscObject) In), &preallocator);
2571: MatSetType(preallocator, MATPREALLOCATOR);
2572: MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
2573: MatSetUp(preallocator);
2574: PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);
2575: for (cell = cStart; cell < cEnd; ++cell) {
2576: if (isRefined) {
2577: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
2578: MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
2579: } else {
2580: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES);
2581: }
2582: }
2583: PetscFree3(vals,cellCIndices,cellFIndices);
2584: MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
2585: MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
2586: MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
2587: MatDestroy(&preallocator);
2588: }
2589: /* Fill matrix */
2590: MatZeroEntries(In);
2591: for (c = cStart; c < cEnd; ++c) {
2592: if (isRefined) {
2593: DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2594: } else {
2595: DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2596: }
2597: }
2598: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);}
2599: PetscFree2(feRef,fvRef);
2600: PetscFree(elemMat);
2601: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2602: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2603: if (mesh->printFEM) {
2604: PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
2605: MatChop(In, 1.0e-10);
2606: MatView(In, NULL);
2607: }
2608: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2609: return(0);
2610: }
2612: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2613: {
2614: SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
2615: }
2617: /*@
2618: DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM.
2620: Input Parameters:
2621: + dmf - The fine mesh
2622: . dmc - The coarse mesh
2623: - user - The user context
2625: Output Parameter:
2626: . In - The interpolation matrix
2628: Level: developer
2630: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
2631: @*/
2632: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2633: {
2634: DM_Plex *mesh = (DM_Plex *) dmf->data;
2635: const char *name = "Interpolator";
2636: PetscDS prob;
2637: PetscSection fsection, csection, globalFSection, globalCSection;
2638: PetscHSetIJ ht;
2639: PetscLayout rLayout;
2640: PetscInt *dnz, *onz;
2641: PetscInt locRows, rStart, rEnd;
2642: PetscReal *x, *v0, *J, *invJ, detJ;
2643: PetscReal *v0c, *Jc, *invJc, detJc;
2644: PetscScalar *elemMat;
2645: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2649: PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2650: DMGetCoordinateDim(dmc, &dim);
2651: DMGetDS(dmc, &prob);
2652: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2653: PetscDSGetNumFields(prob, &Nf);
2654: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2655: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2656: DMGetLocalSection(dmf, &fsection);
2657: DMGetGlobalSection(dmf, &globalFSection);
2658: DMGetLocalSection(dmc, &csection);
2659: DMGetGlobalSection(dmc, &globalCSection);
2660: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2661: PetscDSGetTotalDimension(prob, &totDim);
2662: PetscMalloc1(totDim, &elemMat);
2664: MatGetLocalSize(In, &locRows, NULL);
2665: PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);
2666: PetscLayoutSetLocalSize(rLayout, locRows);
2667: PetscLayoutSetBlockSize(rLayout, 1);
2668: PetscLayoutSetUp(rLayout);
2669: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2670: PetscLayoutDestroy(&rLayout);
2671: PetscCalloc2(locRows,&dnz,locRows,&onz);
2672: PetscHSetIJCreate(&ht);
2673: for (field = 0; field < Nf; ++field) {
2674: PetscObject obj;
2675: PetscClassId id;
2676: PetscDualSpace Q = NULL;
2677: PetscQuadrature f;
2678: const PetscReal *qpoints;
2679: PetscInt Nc, Np, fpdim, i, d;
2681: PetscDSGetDiscretization(prob, field, &obj);
2682: PetscObjectGetClassId(obj, &id);
2683: if (id == PETSCFE_CLASSID) {
2684: PetscFE fe = (PetscFE) obj;
2686: PetscFEGetDualSpace(fe, &Q);
2687: PetscFEGetNumComponents(fe, &Nc);
2688: } else if (id == PETSCFV_CLASSID) {
2689: PetscFV fv = (PetscFV) obj;
2691: PetscFVGetDualSpace(fv, &Q);
2692: Nc = 1;
2693: }
2694: PetscDualSpaceGetDimension(Q, &fpdim);
2695: /* For each fine grid cell */
2696: for (cell = cStart; cell < cEnd; ++cell) {
2697: PetscInt *findices, *cindices;
2698: PetscInt numFIndices, numCIndices;
2700: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2701: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2702: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2703: for (i = 0; i < fpdim; ++i) {
2704: Vec pointVec;
2705: PetscScalar *pV;
2706: PetscSF coarseCellSF = NULL;
2707: const PetscSFNode *coarseCells;
2708: PetscInt numCoarseCells, q, c;
2710: /* Get points from the dual basis functional quadrature */
2711: PetscDualSpaceGetFunctional(Q, i, &f);
2712: PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2713: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2714: VecSetBlockSize(pointVec, dim);
2715: VecGetArray(pointVec, &pV);
2716: for (q = 0; q < Np; ++q) {
2717: const PetscReal xi0[3] = {-1., -1., -1.};
2719: /* Transform point to real space */
2720: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2721: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2722: }
2723: VecRestoreArray(pointVec, &pV);
2724: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2725: /* OPT: Pack all quad points from fine cell */
2726: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2727: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2728: /* Update preallocation info */
2729: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2730: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2731: {
2732: PetscHashIJKey key;
2733: PetscBool missing;
2735: key.i = findices[i];
2736: if (key.i >= 0) {
2737: /* Get indices for coarse elements */
2738: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2739: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2740: for (c = 0; c < numCIndices; ++c) {
2741: key.j = cindices[c];
2742: if (key.j < 0) continue;
2743: PetscHSetIJQueryAdd(ht, key, &missing);
2744: if (missing) {
2745: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2746: else ++onz[key.i-rStart];
2747: }
2748: }
2749: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2750: }
2751: }
2752: }
2753: PetscSFDestroy(&coarseCellSF);
2754: VecDestroy(&pointVec);
2755: }
2756: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2757: }
2758: }
2759: PetscHSetIJDestroy(&ht);
2760: MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);
2761: MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2762: PetscFree2(dnz,onz);
2763: for (field = 0; field < Nf; ++field) {
2764: PetscObject obj;
2765: PetscClassId id;
2766: PetscDualSpace Q = NULL;
2767: PetscTabulation T = NULL;
2768: PetscQuadrature f;
2769: const PetscReal *qpoints, *qweights;
2770: PetscInt Nc, qNc, Np, fpdim, i, d;
2772: PetscDSGetDiscretization(prob, field, &obj);
2773: PetscObjectGetClassId(obj, &id);
2774: if (id == PETSCFE_CLASSID) {
2775: PetscFE fe = (PetscFE) obj;
2777: PetscFEGetDualSpace(fe, &Q);
2778: PetscFEGetNumComponents(fe, &Nc);
2779: PetscFECreateTabulation(fe, 1, 1, x, 0, &T);
2780: } else if (id == PETSCFV_CLASSID) {
2781: PetscFV fv = (PetscFV) obj;
2783: PetscFVGetDualSpace(fv, &Q);
2784: Nc = 1;
2785: } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field);
2786: PetscDualSpaceGetDimension(Q, &fpdim);
2787: /* For each fine grid cell */
2788: for (cell = cStart; cell < cEnd; ++cell) {
2789: PetscInt *findices, *cindices;
2790: PetscInt numFIndices, numCIndices;
2792: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2793: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2794: if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2795: for (i = 0; i < fpdim; ++i) {
2796: Vec pointVec;
2797: PetscScalar *pV;
2798: PetscSF coarseCellSF = NULL;
2799: const PetscSFNode *coarseCells;
2800: PetscInt numCoarseCells, cpdim, q, c, j;
2802: /* Get points from the dual basis functional quadrature */
2803: PetscDualSpaceGetFunctional(Q, i, &f);
2804: PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2805: 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);
2806: VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2807: VecSetBlockSize(pointVec, dim);
2808: VecGetArray(pointVec, &pV);
2809: for (q = 0; q < Np; ++q) {
2810: const PetscReal xi0[3] = {-1., -1., -1.};
2812: /* Transform point to real space */
2813: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2814: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2815: }
2816: VecRestoreArray(pointVec, &pV);
2817: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2818: /* OPT: Read this out from preallocation information */
2819: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2820: /* Update preallocation info */
2821: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2822: if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2823: VecGetArray(pointVec, &pV);
2824: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2825: PetscReal pVReal[3];
2826: const PetscReal xi0[3] = {-1., -1., -1.};
2828: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2829: /* Transform points from real space to coarse reference space */
2830: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2831: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2832: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
2834: if (id == PETSCFE_CLASSID) {
2835: PetscFE fe = (PetscFE) obj;
2837: /* Evaluate coarse basis on contained point */
2838: PetscFEGetDimension(fe, &cpdim);
2839: PetscFEComputeTabulation(fe, 1, x, 0, T);
2840: PetscArrayzero(elemMat, cpdim);
2841: /* Get elemMat entries by multiplying by weight */
2842: for (j = 0; j < cpdim; ++j) {
2843: for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*qweights[ccell*qNc + c];
2844: }
2845: } else {
2846: cpdim = 1;
2847: for (j = 0; j < cpdim; ++j) {
2848: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c];
2849: }
2850: }
2851: /* Update interpolator */
2852: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2853: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2854: MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);
2855: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2856: }
2857: VecRestoreArray(pointVec, &pV);
2858: PetscSFDestroy(&coarseCellSF);
2859: VecDestroy(&pointVec);
2860: }
2861: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2862: }
2863: if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
2864: }
2865: PetscFree3(v0,J,invJ);
2866: PetscFree3(v0c,Jc,invJc);
2867: PetscFree(elemMat);
2868: MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2869: MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2870: PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2871: return(0);
2872: }
2874: /*@
2875: DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM.
2877: Input Parameters:
2878: + dmf - The fine mesh
2879: . dmc - The coarse mesh
2880: - user - The user context
2882: Output Parameter:
2883: . mass - The mass matrix
2885: Level: developer
2887: .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2888: @*/
2889: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2890: {
2891: DM_Plex *mesh = (DM_Plex *) dmf->data;
2892: const char *name = "Mass Matrix";
2893: PetscDS prob;
2894: PetscSection fsection, csection, globalFSection, globalCSection;
2895: PetscHSetIJ ht;
2896: PetscLayout rLayout;
2897: PetscInt *dnz, *onz;
2898: PetscInt locRows, rStart, rEnd;
2899: PetscReal *x, *v0, *J, *invJ, detJ;
2900: PetscReal *v0c, *Jc, *invJc, detJc;
2901: PetscScalar *elemMat;
2902: PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2906: DMGetCoordinateDim(dmc, &dim);
2907: DMGetDS(dmc, &prob);
2908: PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2909: PetscDSGetNumFields(prob, &Nf);
2910: PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2911: PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2912: DMGetLocalSection(dmf, &fsection);
2913: DMGetGlobalSection(dmf, &globalFSection);
2914: DMGetLocalSection(dmc, &csection);
2915: DMGetGlobalSection(dmc, &globalCSection);
2916: DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2917: PetscDSGetTotalDimension(prob, &totDim);
2918: PetscMalloc1(totDim, &elemMat);
2920: MatGetLocalSize(mass, &locRows, NULL);
2921: PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);
2922: PetscLayoutSetLocalSize(rLayout, locRows);
2923: PetscLayoutSetBlockSize(rLayout, 1);
2924: PetscLayoutSetUp(rLayout);
2925: PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2926: PetscLayoutDestroy(&rLayout);
2927: PetscCalloc2(locRows,&dnz,locRows,&onz);
2928: PetscHSetIJCreate(&ht);
2929: for (field = 0; field < Nf; ++field) {
2930: PetscObject obj;
2931: PetscClassId id;
2932: PetscQuadrature quad;
2933: const PetscReal *qpoints;
2934: PetscInt Nq, Nc, i, d;
2936: PetscDSGetDiscretization(prob, field, &obj);
2937: PetscObjectGetClassId(obj, &id);
2938: if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);}
2939: else {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2940: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2941: /* For each fine grid cell */
2942: for (cell = cStart; cell < cEnd; ++cell) {
2943: Vec pointVec;
2944: PetscScalar *pV;
2945: PetscSF coarseCellSF = NULL;
2946: const PetscSFNode *coarseCells;
2947: PetscInt numCoarseCells, q, c;
2948: PetscInt *findices, *cindices;
2949: PetscInt numFIndices, numCIndices;
2951: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2952: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2953: /* Get points from the quadrature */
2954: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2955: VecSetBlockSize(pointVec, dim);
2956: VecGetArray(pointVec, &pV);
2957: for (q = 0; q < Nq; ++q) {
2958: const PetscReal xi0[3] = {-1., -1., -1.};
2960: /* Transform point to real space */
2961: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2962: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2963: }
2964: VecRestoreArray(pointVec, &pV);
2965: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2966: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2967: PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2968: /* Update preallocation info */
2969: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2970: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2971: {
2972: PetscHashIJKey key;
2973: PetscBool missing;
2975: for (i = 0; i < numFIndices; ++i) {
2976: key.i = findices[i];
2977: if (key.i >= 0) {
2978: /* Get indices for coarse elements */
2979: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2980: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2981: for (c = 0; c < numCIndices; ++c) {
2982: key.j = cindices[c];
2983: if (key.j < 0) continue;
2984: PetscHSetIJQueryAdd(ht, key, &missing);
2985: if (missing) {
2986: if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2987: else ++onz[key.i-rStart];
2988: }
2989: }
2990: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2991: }
2992: }
2993: }
2994: }
2995: PetscSFDestroy(&coarseCellSF);
2996: VecDestroy(&pointVec);
2997: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2998: }
2999: }
3000: PetscHSetIJDestroy(&ht);
3001: MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
3002: MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
3003: PetscFree2(dnz,onz);
3004: for (field = 0; field < Nf; ++field) {
3005: PetscObject obj;
3006: PetscClassId id;
3007: PetscTabulation T, Tfine;
3008: PetscQuadrature quad;
3009: const PetscReal *qpoints, *qweights;
3010: PetscInt Nq, Nc, i, d;
3012: PetscDSGetDiscretization(prob, field, &obj);
3013: PetscObjectGetClassId(obj, &id);
3014: if (id == PETSCFE_CLASSID) {
3015: PetscFEGetQuadrature((PetscFE) obj, &quad);
3016: PetscFEGetCellTabulation((PetscFE) obj, 1, &Tfine);
3017: PetscFECreateTabulation((PetscFE) obj, 1, 1, x, 0, &T);
3018: } else {
3019: PetscFVGetQuadrature((PetscFV) obj, &quad);
3020: }
3021: PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
3022: /* For each fine grid cell */
3023: for (cell = cStart; cell < cEnd; ++cell) {
3024: Vec pointVec;
3025: PetscScalar *pV;
3026: PetscSF coarseCellSF = NULL;
3027: const PetscSFNode *coarseCells;
3028: PetscInt numCoarseCells, cpdim, q, c, j;
3029: PetscInt *findices, *cindices;
3030: PetscInt numFIndices, numCIndices;
3032: DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3033: DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
3034: /* Get points from the quadrature */
3035: VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
3036: VecSetBlockSize(pointVec, dim);
3037: VecGetArray(pointVec, &pV);
3038: for (q = 0; q < Nq; ++q) {
3039: const PetscReal xi0[3] = {-1., -1., -1.};
3041: /* Transform point to real space */
3042: CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
3043: for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
3044: }
3045: VecRestoreArray(pointVec, &pV);
3046: /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
3047: DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
3048: /* Update matrix */
3049: PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
3050: if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
3051: VecGetArray(pointVec, &pV);
3052: for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3053: PetscReal pVReal[3];
3054: const PetscReal xi0[3] = {-1., -1., -1.};
3057: DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3058: /* Transform points from real space to coarse reference space */
3059: DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
3060: for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
3061: CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3063: if (id == PETSCFE_CLASSID) {
3064: PetscFE fe = (PetscFE) obj;
3066: /* Evaluate coarse basis on contained point */
3067: PetscFEGetDimension(fe, &cpdim);
3068: PetscFEComputeTabulation(fe, 1, x, 0, T);
3069: /* Get elemMat entries by multiplying by weight */
3070: for (i = 0; i < numFIndices; ++i) {
3071: PetscArrayzero(elemMat, cpdim);
3072: for (j = 0; j < cpdim; ++j) {
3073: 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;
3074: }
3075: /* Update interpolator */
3076: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3077: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3078: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3079: }
3080: } else {
3081: cpdim = 1;
3082: for (i = 0; i < numFIndices; ++i) {
3083: PetscArrayzero(elemMat, cpdim);
3084: for (j = 0; j < cpdim; ++j) {
3085: for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ;
3086: }
3087: /* Update interpolator */
3088: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3089: PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);
3090: if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3091: MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3092: }
3093: }
3094: DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3095: }
3096: VecRestoreArray(pointVec, &pV);
3097: PetscSFDestroy(&coarseCellSF);
3098: VecDestroy(&pointVec);
3099: DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3100: }
3101: if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
3102: }
3103: PetscFree3(v0,J,invJ);
3104: PetscFree3(v0c,Jc,invJc);
3105: PetscFree(elemMat);
3106: MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
3107: MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
3108: return(0);
3109: }
3111: /*@
3112: DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
3114: Input Parameters:
3115: + dmc - The coarse mesh
3116: - dmf - The fine mesh
3117: - user - The user context
3119: Output Parameter:
3120: . sc - The mapping
3122: Level: developer
3124: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
3125: @*/
3126: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3127: {
3128: PetscDS prob;
3129: PetscFE *feRef;
3130: PetscFV *fvRef;
3131: Vec fv, cv;
3132: IS fis, cis;
3133: PetscSection fsection, fglobalSection, csection, cglobalSection;
3134: PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3135: PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
3136: PetscBool *needAvg;
3140: PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3141: DMGetDimension(dmf, &dim);
3142: DMGetLocalSection(dmf, &fsection);
3143: DMGetGlobalSection(dmf, &fglobalSection);
3144: DMGetLocalSection(dmc, &csection);
3145: DMGetGlobalSection(dmc, &cglobalSection);
3146: PetscSectionGetNumFields(fsection, &Nf);
3147: DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
3148: DMGetDS(dmc, &prob);
3149: PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);
3150: for (f = 0; f < Nf; ++f) {
3151: PetscObject obj;
3152: PetscClassId id;
3153: PetscInt fNb = 0, Nc = 0;
3155: PetscDSGetDiscretization(prob, f, &obj);
3156: PetscObjectGetClassId(obj, &id);
3157: if (id == PETSCFE_CLASSID) {
3158: PetscFE fe = (PetscFE) obj;
3159: PetscSpace sp;
3160: PetscInt maxDegree;
3162: PetscFERefine(fe, &feRef[f]);
3163: PetscFEGetDimension(feRef[f], &fNb);
3164: PetscFEGetNumComponents(fe, &Nc);
3165: PetscFEGetBasisSpace(fe, &sp);
3166: PetscSpaceGetDegree(sp, NULL, &maxDegree);
3167: if (!maxDegree) needAvg[f] = PETSC_TRUE;
3168: } else if (id == PETSCFV_CLASSID) {
3169: PetscFV fv = (PetscFV) obj;
3170: PetscDualSpace Q;
3172: PetscFVRefine(fv, &fvRef[f]);
3173: PetscFVGetDualSpace(fvRef[f], &Q);
3174: PetscDualSpaceGetDimension(Q, &fNb);
3175: PetscFVGetNumComponents(fv, &Nc);
3176: needAvg[f] = PETSC_TRUE;
3177: }
3178: fTotDim += fNb;
3179: }
3180: PetscDSGetTotalDimension(prob, &cTotDim);
3181: PetscMalloc1(cTotDim,&cmap);
3182: for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
3183: PetscFE feC;
3184: PetscFV fvC;
3185: PetscDualSpace QF, QC;
3186: PetscInt order = -1, NcF, NcC, fpdim, cpdim;
3188: if (feRef[field]) {
3189: PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);
3190: PetscFEGetNumComponents(feC, &NcC);
3191: PetscFEGetNumComponents(feRef[field], &NcF);
3192: PetscFEGetDualSpace(feRef[field], &QF);
3193: PetscDualSpaceGetOrder(QF, &order);
3194: PetscDualSpaceGetDimension(QF, &fpdim);
3195: PetscFEGetDualSpace(feC, &QC);
3196: PetscDualSpaceGetDimension(QC, &cpdim);
3197: } else {
3198: PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);
3199: PetscFVGetNumComponents(fvC, &NcC);
3200: PetscFVGetNumComponents(fvRef[field], &NcF);
3201: PetscFVGetDualSpace(fvRef[field], &QF);
3202: PetscDualSpaceGetDimension(QF, &fpdim);
3203: PetscFVGetDualSpace(fvC, &QC);
3204: PetscDualSpaceGetDimension(QC, &cpdim);
3205: }
3206: 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);
3207: for (c = 0; c < cpdim; ++c) {
3208: PetscQuadrature cfunc;
3209: const PetscReal *cqpoints, *cqweights;
3210: PetscInt NqcC, NpC;
3211: PetscBool found = PETSC_FALSE;
3213: PetscDualSpaceGetFunctional(QC, c, &cfunc);
3214: PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
3215: 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);
3216: if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
3217: for (f = 0; f < fpdim; ++f) {
3218: PetscQuadrature ffunc;
3219: const PetscReal *fqpoints, *fqweights;
3220: PetscReal sum = 0.0;
3221: PetscInt NqcF, NpF;
3223: PetscDualSpaceGetFunctional(QF, f, &ffunc);
3224: PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
3225: 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);
3226: if (NpC != NpF) continue;
3227: for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
3228: if (sum > 1.0e-9) continue;
3229: for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
3230: if (sum < 1.0e-9) continue;
3231: cmap[offsetC+c] = offsetF+f;
3232: found = PETSC_TRUE;
3233: break;
3234: }
3235: if (!found) {
3236: /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3237: if (fvRef[field] || (feRef[field] && order == 0)) {
3238: cmap[offsetC+c] = offsetF+0;
3239: } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3240: }
3241: }
3242: offsetC += cpdim;
3243: offsetF += fpdim;
3244: }
3245: for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
3246: PetscFree3(feRef,fvRef,needAvg);
3248: DMGetGlobalVector(dmf, &fv);
3249: DMGetGlobalVector(dmc, &cv);
3250: VecGetOwnershipRange(cv, &startC, &endC);
3251: PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
3252: PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);
3253: PetscMalloc1(m,&cindices);
3254: PetscMalloc1(m,&findices);
3255: for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
3256: for (c = cStart; c < cEnd; ++c) {
3257: DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
3258: for (d = 0; d < cTotDim; ++d) {
3259: if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3260: 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]]);
3261: cindices[cellCIndices[d]-startC] = cellCIndices[d];
3262: findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
3263: }
3264: }
3265: PetscFree(cmap);
3266: PetscFree2(cellCIndices,cellFIndices);
3268: ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
3269: ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
3270: VecScatterCreate(cv, cis, fv, fis, sc);
3271: ISDestroy(&cis);
3272: ISDestroy(&fis);
3273: DMRestoreGlobalVector(dmf, &fv);
3274: DMRestoreGlobalVector(dmc, &cv);
3275: PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3276: return(0);
3277: }
3279: /*@C
3280: DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
3282: Input Parameters:
3283: + dm - The DM
3284: . cellIS - The cells to include
3285: . locX - A local vector with the solution fields
3286: . locX_t - A local vector with solution field time derivatives, or NULL
3287: - locA - A local vector with auxiliary fields, or NULL
3289: Output Parameters:
3290: + u - The field coefficients
3291: . u_t - The fields derivative coefficients
3292: - a - The auxiliary field coefficients
3294: Level: developer
3296: .seealso: DMPlexGetFaceFields()
3297: @*/
3298: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3299: {
3300: DM plex, plexA = NULL;
3301: DMEnclosureType encAux;
3302: PetscSection section, sectionAux;
3303: PetscDS prob;
3304: const PetscInt *cells;
3305: PetscInt cStart, cEnd, numCells, totDim, totDimAux, c;
3306: PetscErrorCode ierr;
3316: DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
3317: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3318: DMGetLocalSection(dm, §ion);
3319: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
3320: PetscDSGetTotalDimension(prob, &totDim);
3321: if (locA) {
3322: DM dmAux;
3323: PetscDS probAux;
3325: VecGetDM(locA, &dmAux);
3326: DMGetEnclosureRelation(dmAux, dm, &encAux);
3327: DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3328: DMGetLocalSection(dmAux, §ionAux);
3329: DMGetDS(dmAux, &probAux);
3330: PetscDSGetTotalDimension(probAux, &totDimAux);
3331: }
3332: numCells = cEnd - cStart;
3333: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);
3334: if (locX_t) {DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);} else {*u_t = NULL;}
3335: if (locA) {DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);} else {*a = NULL;}
3336: for (c = cStart; c < cEnd; ++c) {
3337: const PetscInt cell = cells ? cells[c] : c;
3338: const PetscInt cind = c - cStart;
3339: PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
3340: PetscInt i;
3342: DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
3343: for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i];
3344: DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
3345: if (locX_t) {
3346: DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
3347: for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i];
3348: DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
3349: }
3350: if (locA) {
3351: PetscInt subcell;
3352: DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell);
3353: DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3354: for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i];
3355: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3356: }
3357: }
3358: DMDestroy(&plex);
3359: if (locA) {DMDestroy(&plexA);}
3360: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3361: return(0);
3362: }
3364: /*@C
3365: DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
3367: Input Parameters:
3368: + dm - The DM
3369: . cellIS - The cells to include
3370: . locX - A local vector with the solution fields
3371: . locX_t - A local vector with solution field time derivatives, or NULL
3372: - locA - A local vector with auxiliary fields, or NULL
3374: Output Parameters:
3375: + u - The field coefficients
3376: . u_t - The fields derivative coefficients
3377: - a - The auxiliary field coefficients
3379: Level: developer
3381: .seealso: DMPlexGetFaceFields()
3382: @*/
3383: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3384: {
3388: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
3389: if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
3390: if (locA) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
3391: return(0);
3392: }
3394: static PetscErrorCode DMPlexGetHybridAuxFields(DM dmAux, PetscDS dsAux[], IS cellIS, Vec locA, PetscScalar *a[])
3395: {
3396: DM plexA;
3397: PetscSection sectionAux;
3398: const PetscInt *cells;
3399: PetscInt cStart, cEnd, numCells, c, totDimAux[2];
3400: PetscErrorCode ierr;
3403: if (!locA) return(0);
3408: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3409: DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3410: DMGetLocalSection(dmAux, §ionAux);
3411: numCells = cEnd - cStart;
3412: PetscDSGetTotalDimension(dsAux[0], &totDimAux[0]);
3413: DMGetWorkArray(dmAux, numCells*totDimAux[0], MPIU_SCALAR, &a[0]);
3414: PetscDSGetTotalDimension(dsAux[1], &totDimAux[1]);
3415: DMGetWorkArray(dmAux, numCells*totDimAux[1], MPIU_SCALAR, &a[1]);
3416: for (c = cStart; c < cEnd; ++c) {
3417: const PetscInt cell = cells ? cells[c] : c;
3418: const PetscInt cind = c - cStart;
3419: const PetscInt *cone, *ornt;
3420: PetscInt c;
3422: DMPlexGetCone(dmAux, cell, &cone);
3423: DMPlexGetConeOrientation(dmAux, cell, &ornt);
3424: for (c = 0; c < 2; ++c) {
3425: PetscScalar *x = NULL, *al = a[c];
3426: const PetscInt tdA = totDimAux[c];
3427: PetscInt Na, i;
3429: if (ornt[c]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %D in hybrid cell %D has orientation %D != 0", cone[c], cell, ornt[c]);
3430: DMPlexVecGetClosure(plexA, sectionAux, locA, cone[c], &Na, &x);
3431: for (i = 0; i < Na; ++i) al[cind*tdA+i] = x[i];
3432: DMPlexVecRestoreClosure(plexA, sectionAux, locA, cone[c], &Na, &x);
3433: }
3434: }
3435: DMDestroy(&plexA);
3436: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3437: return(0);
3438: }
3440: static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux, PetscDS dsAux[], IS cellIS, Vec locA, PetscScalar *a[])
3441: {
3445: if (!locA) return(0);
3446: DMRestoreWorkArray(dmAux, 0, MPIU_SCALAR, &a[0]);
3447: DMRestoreWorkArray(dmAux, 0, MPIU_SCALAR, &a[1]);
3448: return(0);
3449: }
3451: /*@C
3452: DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
3454: Input Parameters:
3455: + dm - The DM
3456: . fStart - The first face to include
3457: . fEnd - The first face to exclude
3458: . locX - A local vector with the solution fields
3459: . locX_t - A local vector with solution field time derivatives, or NULL
3460: . faceGeometry - A local vector with face geometry
3461: . cellGeometry - A local vector with cell geometry
3462: - locaGrad - A local vector with field gradients, or NULL
3464: Output Parameters:
3465: + Nface - The number of faces with field values
3466: . uL - The field values at the left side of the face
3467: - uR - The field values at the right side of the face
3469: Level: developer
3471: .seealso: DMPlexGetCellFields()
3472: @*/
3473: 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)
3474: {
3475: DM dmFace, dmCell, dmGrad = NULL;
3476: PetscSection section;
3477: PetscDS prob;
3478: DMLabel ghostLabel;
3479: const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
3480: PetscBool *isFE;
3481: PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
3482: PetscErrorCode ierr;
3493: DMGetDimension(dm, &dim);
3494: DMGetDS(dm, &prob);
3495: DMGetLocalSection(dm, §ion);
3496: PetscDSGetNumFields(prob, &Nf);
3497: PetscDSGetTotalComponents(prob, &Nc);
3498: PetscMalloc1(Nf, &isFE);
3499: for (f = 0; f < Nf; ++f) {
3500: PetscObject obj;
3501: PetscClassId id;
3503: PetscDSGetDiscretization(prob, f, &obj);
3504: PetscObjectGetClassId(obj, &id);
3505: if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;}
3506: else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3507: else {isFE[f] = PETSC_FALSE;}
3508: }
3509: DMGetLabel(dm, "ghost", &ghostLabel);
3510: VecGetArrayRead(locX, &x);
3511: VecGetDM(faceGeometry, &dmFace);
3512: VecGetArrayRead(faceGeometry, &facegeom);
3513: VecGetDM(cellGeometry, &dmCell);
3514: VecGetArrayRead(cellGeometry, &cellgeom);
3515: if (locGrad) {
3516: VecGetDM(locGrad, &dmGrad);
3517: VecGetArrayRead(locGrad, &lgrad);
3518: }
3519: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
3520: DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
3521: /* Right now just eat the extra work for FE (could make a cell loop) */
3522: for (face = fStart, iface = 0; face < fEnd; ++face) {
3523: const PetscInt *cells;
3524: PetscFVFaceGeom *fg;
3525: PetscFVCellGeom *cgL, *cgR;
3526: PetscScalar *xL, *xR, *gL, *gR;
3527: PetscScalar *uLl = *uL, *uRl = *uR;
3528: PetscInt ghost, nsupp, nchild;
3530: DMLabelGetValue(ghostLabel, face, &ghost);
3531: DMPlexGetSupportSize(dm, face, &nsupp);
3532: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3533: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3534: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3535: DMPlexGetSupport(dm, face, &cells);
3536: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3537: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3538: for (f = 0; f < Nf; ++f) {
3539: PetscInt off;
3541: PetscDSGetComponentOffset(prob, f, &off);
3542: if (isFE[f]) {
3543: const PetscInt *cone;
3544: PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
3546: xL = xR = NULL;
3547: PetscSectionGetFieldComponents(section, f, &comp);
3548: DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3549: DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3550: DMPlexGetCone(dm, cells[0], &cone);
3551: DMPlexGetConeSize(dm, cells[0], &coneSizeL);
3552: for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
3553: DMPlexGetCone(dm, cells[1], &cone);
3554: DMPlexGetConeSize(dm, cells[1], &coneSizeR);
3555: for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
3556: 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]);
3557: /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
3558: /* TODO: this is a hack that might not be right for nonconforming */
3559: if (faceLocL < coneSizeL) {
3560: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
3561: if (rdof == ldof && faceLocR < coneSizeR) {PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
3562: else {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
3563: }
3564: else {
3565: PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
3566: PetscSectionGetFieldComponents(section, f, &comp);
3567: for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
3568: }
3569: DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3570: DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3571: } else {
3572: PetscFV fv;
3573: PetscInt numComp, c;
3575: PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
3576: PetscFVGetNumComponents(fv, &numComp);
3577: DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3578: DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3579: if (dmGrad) {
3580: PetscReal dxL[3], dxR[3];
3582: DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
3583: DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
3584: DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
3585: DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
3586: for (c = 0; c < numComp; ++c) {
3587: uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
3588: uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
3589: }
3590: } else {
3591: for (c = 0; c < numComp; ++c) {
3592: uLl[iface*Nc+off+c] = xL[c];
3593: uRl[iface*Nc+off+c] = xR[c];
3594: }
3595: }
3596: }
3597: }
3598: ++iface;
3599: }
3600: *Nface = iface;
3601: VecRestoreArrayRead(locX, &x);
3602: VecRestoreArrayRead(faceGeometry, &facegeom);
3603: VecRestoreArrayRead(cellGeometry, &cellgeom);
3604: if (locGrad) {
3605: VecRestoreArrayRead(locGrad, &lgrad);
3606: }
3607: PetscFree(isFE);
3608: return(0);
3609: }
3611: /*@C
3612: DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
3614: Input Parameters:
3615: + dm - The DM
3616: . fStart - The first face to include
3617: . fEnd - The first face to exclude
3618: . locX - A local vector with the solution fields
3619: . locX_t - A local vector with solution field time derivatives, or NULL
3620: . faceGeometry - A local vector with face geometry
3621: . cellGeometry - A local vector with cell geometry
3622: - locaGrad - A local vector with field gradients, or NULL
3624: Output Parameters:
3625: + Nface - The number of faces with field values
3626: . uL - The field values at the left side of the face
3627: - uR - The field values at the right side of the face
3629: Level: developer
3631: .seealso: DMPlexGetFaceFields()
3632: @*/
3633: 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)
3634: {
3638: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3639: DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3640: return(0);
3641: }
3643: /*@C
3644: DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
3646: Input Parameters:
3647: + dm - The DM
3648: . fStart - The first face to include
3649: . fEnd - The first face to exclude
3650: . faceGeometry - A local vector with face geometry
3651: - cellGeometry - A local vector with cell geometry
3653: Output Parameters:
3654: + Nface - The number of faces with field values
3655: . fgeom - The extract the face centroid and normal
3656: - vol - The cell volume
3658: Level: developer
3660: .seealso: DMPlexGetCellFields()
3661: @*/
3662: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3663: {
3664: DM dmFace, dmCell;
3665: DMLabel ghostLabel;
3666: const PetscScalar *facegeom, *cellgeom;
3667: PetscInt dim, numFaces = fEnd - fStart, iface, face;
3668: PetscErrorCode ierr;
3676: DMGetDimension(dm, &dim);
3677: DMGetLabel(dm, "ghost", &ghostLabel);
3678: VecGetDM(faceGeometry, &dmFace);
3679: VecGetArrayRead(faceGeometry, &facegeom);
3680: VecGetDM(cellGeometry, &dmCell);
3681: VecGetArrayRead(cellGeometry, &cellgeom);
3682: PetscMalloc1(numFaces, fgeom);
3683: DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
3684: for (face = fStart, iface = 0; face < fEnd; ++face) {
3685: const PetscInt *cells;
3686: PetscFVFaceGeom *fg;
3687: PetscFVCellGeom *cgL, *cgR;
3688: PetscFVFaceGeom *fgeoml = *fgeom;
3689: PetscReal *voll = *vol;
3690: PetscInt ghost, d, nchild, nsupp;
3692: DMLabelGetValue(ghostLabel, face, &ghost);
3693: DMPlexGetSupportSize(dm, face, &nsupp);
3694: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3695: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3696: DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3697: DMPlexGetSupport(dm, face, &cells);
3698: DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3699: DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3700: for (d = 0; d < dim; ++d) {
3701: fgeoml[iface].centroid[d] = fg->centroid[d];
3702: fgeoml[iface].normal[d] = fg->normal[d];
3703: }
3704: voll[iface*2+0] = cgL->volume;
3705: voll[iface*2+1] = cgR->volume;
3706: ++iface;
3707: }
3708: *Nface = iface;
3709: VecRestoreArrayRead(faceGeometry, &facegeom);
3710: VecRestoreArrayRead(cellGeometry, &cellgeom);
3711: return(0);
3712: }
3714: /*@C
3715: DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
3717: Input Parameters:
3718: + dm - The DM
3719: . fStart - The first face to include
3720: . fEnd - The first face to exclude
3721: . faceGeometry - A local vector with face geometry
3722: - cellGeometry - A local vector with cell geometry
3724: Output Parameters:
3725: + Nface - The number of faces with field values
3726: . fgeom - The extract the face centroid and normal
3727: - vol - The cell volume
3729: Level: developer
3731: .seealso: DMPlexGetFaceFields()
3732: @*/
3733: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3734: {
3738: PetscFree(*fgeom);
3739: DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3740: return(0);
3741: }
3743: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3744: {
3745: char composeStr[33] = {0};
3746: PetscObjectId id;
3747: PetscContainer container;
3748: PetscErrorCode ierr;
3751: PetscObjectGetId((PetscObject)quad,&id);
3752: PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3753: PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3754: if (container) {
3755: PetscContainerGetPointer(container, (void **) geom);
3756: } else {
3757: DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3758: PetscContainerCreate(PETSC_COMM_SELF,&container);
3759: PetscContainerSetPointer(container, (void *) *geom);
3760: PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3761: PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3762: PetscContainerDestroy(&container);
3763: }
3764: return(0);
3765: }
3767: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3768: {
3770: *geom = NULL;
3771: return(0);
3772: }
3774: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3775: {
3776: DM_Plex *mesh = (DM_Plex *) dm->data;
3777: const char *name = "Residual";
3778: DM dmAux = NULL;
3779: DMLabel ghostLabel = NULL;
3780: PetscDS prob = NULL;
3781: PetscDS probAux = NULL;
3782: PetscBool useFEM = PETSC_FALSE;
3783: PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3784: DMField coordField = NULL;
3785: Vec locA;
3786: PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3787: IS chunkIS;
3788: const PetscInt *cells;
3789: PetscInt cStart, cEnd, numCells;
3790: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3791: PetscInt maxDegree = PETSC_MAX_INT;
3792: PetscHashFormKey key;
3793: PetscQuadrature affineQuad = NULL, *quads = NULL;
3794: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
3795: PetscErrorCode ierr;
3798: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3799: /* FEM+FVM */
3800: /* 1: Get sizes from dm and dmAux */
3801: DMGetLabel(dm, "ghost", &ghostLabel);
3802: DMGetDS(dm, &prob);
3803: PetscDSGetNumFields(prob, &Nf);
3804: PetscDSGetTotalDimension(prob, &totDim);
3805: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
3806: if (locA) {
3807: VecGetDM(locA, &dmAux);
3808: DMGetDS(dmAux, &probAux);
3809: PetscDSGetTotalDimension(probAux, &totDimAux);
3810: }
3811: /* 2: Get geometric data */
3812: for (f = 0; f < Nf; ++f) {
3813: PetscObject obj;
3814: PetscClassId id;
3815: PetscBool fimp;
3817: PetscDSGetImplicit(prob, f, &fimp);
3818: if (isImplicit != fimp) continue;
3819: PetscDSGetDiscretization(prob, f, &obj);
3820: PetscObjectGetClassId(obj, &id);
3821: if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3822: if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3823: }
3824: if (useFEM) {
3825: DMGetCoordinateField(dm, &coordField);
3826: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3827: if (maxDegree <= 1) {
3828: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3829: if (affineQuad) {
3830: DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3831: }
3832: } else {
3833: PetscCalloc2(Nf,&quads,Nf,&geoms);
3834: for (f = 0; f < Nf; ++f) {
3835: PetscObject obj;
3836: PetscClassId id;
3837: PetscBool fimp;
3839: PetscDSGetImplicit(prob, f, &fimp);
3840: if (isImplicit != fimp) continue;
3841: PetscDSGetDiscretization(prob, f, &obj);
3842: PetscObjectGetClassId(obj, &id);
3843: if (id == PETSCFE_CLASSID) {
3844: PetscFE fe = (PetscFE) obj;
3846: PetscFEGetQuadrature(fe, &quads[f]);
3847: PetscObjectReference((PetscObject)quads[f]);
3848: DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3849: }
3850: }
3851: }
3852: }
3853: /* Loop over chunks */
3854: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3855: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3856: if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3857: numCells = cEnd - cStart;
3858: numChunks = 1;
3859: cellChunkSize = numCells/numChunks;
3860: numChunks = PetscMin(1,numCells);
3861: key.label = NULL;
3862: key.value = 0;
3863: for (chunk = 0; chunk < numChunks; ++chunk) {
3864: PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL;
3865: PetscReal *vol = NULL;
3866: PetscFVFaceGeom *fgeom = NULL;
3867: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3868: PetscInt numFaces = 0;
3870: /* Extract field coefficients */
3871: if (useFEM) {
3872: ISGetPointSubrange(chunkIS, cS, cE, cells);
3873: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3874: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3875: PetscArrayzero(elemVec, numCells*totDim);
3876: }
3877: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3878: /* Loop over fields */
3879: for (f = 0; f < Nf; ++f) {
3880: PetscObject obj;
3881: PetscClassId id;
3882: PetscBool fimp;
3883: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
3885: key.field = f;
3886: PetscDSGetImplicit(prob, f, &fimp);
3887: if (isImplicit != fimp) continue;
3888: PetscDSGetDiscretization(prob, f, &obj);
3889: PetscObjectGetClassId(obj, &id);
3890: if (id == PETSCFE_CLASSID) {
3891: PetscFE fe = (PetscFE) obj;
3892: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
3893: PetscFEGeom *chunkGeom = NULL;
3894: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3895: PetscInt Nq, Nb;
3897: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3898: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3899: PetscFEGetDimension(fe, &Nb);
3900: blockSize = Nb;
3901: batchSize = numBlocks * blockSize;
3902: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3903: numChunks = numCells / (numBatches*batchSize);
3904: Ne = numChunks*numBatches*batchSize;
3905: Nr = numCells % (numBatches*batchSize);
3906: offset = numCells - Nr;
3907: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3908: /* 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) */
3909: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3910: PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3911: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3912: PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3913: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3914: } else if (id == PETSCFV_CLASSID) {
3915: PetscFV fv = (PetscFV) obj;
3917: Ne = numFaces;
3918: /* Riemann solve over faces (need fields at face centroids) */
3919: /* We need to evaluate FE fields at those coordinates */
3920: PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3921: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
3922: }
3923: /* Loop over domain */
3924: if (useFEM) {
3925: /* Add elemVec to locX */
3926: for (c = cS; c < cE; ++c) {
3927: const PetscInt cell = cells ? cells[c] : c;
3928: const PetscInt cind = c - cStart;
3930: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
3931: if (ghostLabel) {
3932: PetscInt ghostVal;
3934: DMLabelGetValue(ghostLabel,cell,&ghostVal);
3935: if (ghostVal > 0) continue;
3936: }
3937: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3938: }
3939: }
3940: /* Handle time derivative */
3941: if (locX_t) {
3942: PetscScalar *x_t, *fa;
3944: VecGetArray(locF, &fa);
3945: VecGetArray(locX_t, &x_t);
3946: for (f = 0; f < Nf; ++f) {
3947: PetscFV fv;
3948: PetscObject obj;
3949: PetscClassId id;
3950: PetscInt pdim, d;
3952: PetscDSGetDiscretization(prob, f, &obj);
3953: PetscObjectGetClassId(obj, &id);
3954: if (id != PETSCFV_CLASSID) continue;
3955: fv = (PetscFV) obj;
3956: PetscFVGetNumComponents(fv, &pdim);
3957: for (c = cS; c < cE; ++c) {
3958: const PetscInt cell = cells ? cells[c] : c;
3959: PetscScalar *u_t, *r;
3961: if (ghostLabel) {
3962: PetscInt ghostVal;
3964: DMLabelGetValue(ghostLabel, cell, &ghostVal);
3965: if (ghostVal > 0) continue;
3966: }
3967: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3968: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3969: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3970: }
3971: }
3972: VecRestoreArray(locX_t, &x_t);
3973: VecRestoreArray(locF, &fa);
3974: }
3975: if (useFEM) {
3976: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3977: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3978: }
3979: }
3980: if (useFEM) {ISDestroy(&chunkIS);}
3981: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3982: /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3983: if (useFEM) {
3984: if (maxDegree <= 1) {
3985: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3986: PetscQuadratureDestroy(&affineQuad);
3987: } else {
3988: for (f = 0; f < Nf; ++f) {
3989: DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3990: PetscQuadratureDestroy(&quads[f]);
3991: }
3992: PetscFree2(quads,geoms);
3993: }
3994: }
3995: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
3996: return(0);
3997: }
3999: /*
4000: 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
4002: X - The local solution vector
4003: X_t - The local solution time derviative vector, or NULL
4004: */
4005: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
4006: PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
4007: {
4008: DM_Plex *mesh = (DM_Plex *) dm->data;
4009: const char *name = "Jacobian", *nameP = "JacobianPre";
4010: DM dmAux = NULL;
4011: PetscDS prob, probAux = NULL;
4012: PetscSection sectionAux = NULL;
4013: Vec A;
4014: DMField coordField;
4015: PetscFEGeom *cgeomFEM;
4016: PetscQuadrature qGeom = NULL;
4017: Mat J = Jac, JP = JacP;
4018: PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4019: PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
4020: const PetscInt *cells;
4021: PetscHashFormKey key;
4022: PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4023: PetscErrorCode ierr;
4026: CHKMEMQ;
4027: ISGetLocalSize(cellIS, &numCells);
4028: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4029: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
4030: DMGetDS(dm, &prob);
4031: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
4032: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
4033: if (dmAux) {
4034: DMGetLocalSection(dmAux, §ionAux);
4035: DMGetDS(dmAux, &probAux);
4036: }
4037: /* Get flags */
4038: PetscDSGetNumFields(prob, &Nf);
4039: DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4040: for (fieldI = 0; fieldI < Nf; ++fieldI) {
4041: PetscObject disc;
4042: PetscClassId id;
4043: PetscDSGetDiscretization(prob, fieldI, &disc);
4044: PetscObjectGetClassId(disc, &id);
4045: if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;}
4046: else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
4047: }
4048: PetscDSHasJacobian(prob, &hasJac);
4049: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
4050: PetscDSHasDynamicJacobian(prob, &hasDyn);
4051: assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4052: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
4053: PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);
4054: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
4055: /* Setup input data and temp arrays (should be DMGetWorkArray) */
4056: if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
4057: if (isMatIS) {MatISGetLocalMat(Jac, &J);}
4058: if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
4059: if (hasFV) {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
4060: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
4061: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
4062: PetscDSGetTotalDimension(prob, &totDim);
4063: if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
4064: CHKMEMQ;
4065: /* Compute batch sizes */
4066: if (isFE[0]) {
4067: PetscFE fe;
4068: PetscQuadrature q;
4069: PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4071: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4072: PetscFEGetQuadrature(fe, &q);
4073: PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
4074: PetscFEGetDimension(fe, &Nb);
4075: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4076: blockSize = Nb*numQuadPoints;
4077: batchSize = numBlocks * blockSize;
4078: chunkSize = numBatches * batchSize;
4079: numChunks = numCells / chunkSize + numCells % chunkSize;
4080: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4081: } else {
4082: chunkSize = numCells;
4083: numChunks = 1;
4084: }
4085: /* Get work space */
4086: wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
4087: DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
4088: PetscArrayzero(work, wsz);
4089: off = 0;
4090: u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
4091: u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL;
4092: a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL;
4093: elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4094: elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4095: elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4096: if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
4097: /* Setup geometry */
4098: DMGetCoordinateField(dm, &coordField);
4099: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4100: if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
4101: if (!qGeom) {
4102: PetscFE fe;
4104: PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4105: PetscFEGetQuadrature(fe, &qGeom);
4106: PetscObjectReference((PetscObject) qGeom);
4107: }
4108: DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4109: /* Compute volume integrals */
4110: if (assembleJac) {MatZeroEntries(J);}
4111: MatZeroEntries(JP);
4112: key.label = NULL;
4113: key.value = 0;
4114: for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4115: const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4116: PetscInt c;
4118: /* Extract values */
4119: for (c = 0; c < Ncell; ++c) {
4120: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4121: PetscScalar *x = NULL, *x_t = NULL;
4122: PetscInt i;
4124: if (X) {
4125: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
4126: for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
4127: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
4128: }
4129: if (X_t) {
4130: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
4131: for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
4132: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
4133: }
4134: if (dmAux) {
4135: DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
4136: for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
4137: DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
4138: }
4139: }
4140: CHKMEMQ;
4141: for (fieldI = 0; fieldI < Nf; ++fieldI) {
4142: PetscFE fe;
4143: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
4144: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
4145: key.field = fieldI*Nf + fieldJ;
4146: if (hasJac) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
4147: if (hasPrec) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
4148: if (hasDyn) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
4149: }
4150: /* For finite volume, add the identity */
4151: if (!isFE[fieldI]) {
4152: PetscFV fv;
4153: PetscInt eOffset = 0, Nc, fc, foff;
4155: PetscDSGetFieldOffset(prob, fieldI, &foff);
4156: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
4157: PetscFVGetNumComponents(fv, &Nc);
4158: for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
4159: for (fc = 0; fc < Nc; ++fc) {
4160: const PetscInt i = foff + fc;
4161: if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;}
4162: if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
4163: }
4164: }
4165: }
4166: }
4167: CHKMEMQ;
4168: /* Add contribution from X_t */
4169: if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
4170: /* Insert values into matrix */
4171: for (c = 0; c < Ncell; ++c) {
4172: const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4173: if (mesh->printFEM > 1) {
4174: if (hasJac) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
4175: if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
4176: }
4177: if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
4178: DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
4179: }
4180: CHKMEMQ;
4181: }
4182: /* Cleanup */
4183: DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4184: PetscQuadratureDestroy(&qGeom);
4185: if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
4186: DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4187: 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);
4188: /* Compute boundary integrals */
4189: /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
4190: /* Assemble matrix */
4191: if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
4192: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
4193: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
4194: CHKMEMQ;
4195: return(0);
4196: }
4198: /******** FEM Assembly Function ********/
4200: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4201: {
4202: PetscBool isPlex;
4206: PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
4207: if (isPlex) {
4208: *plex = dm;
4209: PetscObjectReference((PetscObject) dm);
4210: } else {
4211: PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
4212: if (!*plex) {
4213: DMConvert(dm,DMPLEX,plex);
4214: PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
4215: if (copy) {
4216: const char *comps[] = {"A", "dmAux"};
4217: PetscObject obj;
4218: PetscInt i;
4220: for (i = 0; i < 2; ++i) {
4221: PetscObjectQuery((PetscObject) dm, comps[i], &obj);
4222: PetscObjectCompose((PetscObject) *plex, comps[i], obj);
4223: }
4224: }
4225: } else {
4226: PetscObjectReference((PetscObject) *plex);
4227: }
4228: }
4229: return(0);
4230: }
4232: /*@
4233: DMPlexGetGeometryFVM - Return precomputed geometric data
4235: Collective on DM
4237: Input Parameter:
4238: . dm - The DM
4240: Output Parameters:
4241: + facegeom - The values precomputed from face geometry
4242: . cellgeom - The values precomputed from cell geometry
4243: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell
4245: Level: developer
4247: .seealso: DMTSSetRHSFunctionLocal()
4248: @*/
4249: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4250: {
4251: DM plex;
4256: DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4257: DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4258: if (minRadius) {DMPlexGetMinRadius(plex, minRadius);}
4259: DMDestroy(&plex);
4260: return(0);
4261: }
4263: /*@
4264: DMPlexGetGradientDM - Return gradient data layout
4266: Collective on DM
4268: Input Parameters:
4269: + dm - The DM
4270: - fv - The PetscFV
4272: Output Parameter:
4273: . dmGrad - The layout for gradient values
4275: Level: developer
4277: .seealso: DMPlexGetGeometryFVM()
4278: @*/
4279: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4280: {
4281: DM plex;
4282: PetscBool computeGradients;
4289: PetscFVGetComputeGradients(fv, &computeGradients);
4290: if (!computeGradients) {*dmGrad = NULL; return(0);}
4291: DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4292: DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4293: DMDestroy(&plex);
4294: return(0);
4295: }
4297: 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)
4298: {
4299: DM_Plex *mesh = (DM_Plex *) dm->data;
4300: DM plex = NULL, plexA = NULL;
4301: DMEnclosureType encAux;
4302: PetscDS prob, probAux = NULL;
4303: PetscSection section, sectionAux = NULL;
4304: Vec locA = NULL;
4305: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4306: PetscInt v;
4307: PetscInt totDim, totDimAux = 0;
4308: PetscErrorCode ierr;
4311: DMConvert(dm, DMPLEX, &plex);
4312: DMGetLocalSection(dm, §ion);
4313: DMGetDS(dm, &prob);
4314: PetscDSGetTotalDimension(prob, &totDim);
4315: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4316: if (locA) {
4317: DM dmAux;
4319: VecGetDM(locA, &dmAux);
4320: DMGetEnclosureRelation(dmAux, dm, &encAux);
4321: DMConvert(dmAux, DMPLEX, &plexA);
4322: DMGetDS(plexA, &probAux);
4323: PetscDSGetTotalDimension(probAux, &totDimAux);
4324: DMGetLocalSection(plexA, §ionAux);
4325: }
4326: for (v = 0; v < numValues; ++v) {
4327: PetscFEGeom *fgeom;
4328: PetscInt maxDegree;
4329: PetscQuadrature qGeom = NULL;
4330: IS pointIS;
4331: const PetscInt *points;
4332: PetscInt numFaces, face, Nq;
4334: DMLabelGetStratumIS(label, values[v], &pointIS);
4335: if (!pointIS) continue; /* No points with that id on this process */
4336: {
4337: IS isectIS;
4339: /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
4340: ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4341: ISDestroy(&pointIS);
4342: pointIS = isectIS;
4343: }
4344: ISGetLocalSize(pointIS,&numFaces);
4345: ISGetIndices(pointIS,&points);
4346: PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a);
4347: DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4348: if (maxDegree <= 1) {
4349: DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4350: }
4351: if (!qGeom) {
4352: PetscFE fe;
4354: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4355: PetscFEGetFaceQuadrature(fe, &qGeom);
4356: PetscObjectReference((PetscObject)qGeom);
4357: }
4358: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
4359: DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4360: for (face = 0; face < numFaces; ++face) {
4361: const PetscInt point = points[face], *support;
4362: PetscScalar *x = NULL;
4363: PetscInt i;
4365: DMPlexGetSupport(dm, point, &support);
4366: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
4367: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
4368: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
4369: if (locX_t) {
4370: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
4371: for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
4372: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
4373: }
4374: if (locA) {
4375: PetscInt subp;
4377: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
4378: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
4379: for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
4380: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
4381: }
4382: }
4383: PetscArrayzero(elemVec, numFaces*totDim);
4384: {
4385: PetscFE fe;
4386: PetscInt Nb;
4387: PetscFEGeom *chunkGeom = NULL;
4388: /* Conforming batches */
4389: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
4390: /* Remainder */
4391: PetscInt Nr, offset;
4393: PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4394: PetscFEGetDimension(fe, &Nb);
4395: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4396: /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
4397: blockSize = Nb;
4398: batchSize = numBlocks * blockSize;
4399: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4400: numChunks = numFaces / (numBatches*batchSize);
4401: Ne = numChunks*numBatches*batchSize;
4402: Nr = numFaces % (numBatches*batchSize);
4403: offset = numFaces - Nr;
4404: PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
4405: PetscFEIntegrateBdResidual(prob, field, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4406: PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
4407: PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
4408: 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]);
4409: PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
4410: }
4411: for (face = 0; face < numFaces; ++face) {
4412: const PetscInt point = points[face], *support;
4414: if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim]);}
4415: DMPlexGetSupport(plex, point, &support);
4416: DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES);
4417: }
4418: DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4419: PetscQuadratureDestroy(&qGeom);
4420: ISRestoreIndices(pointIS, &points);
4421: ISDestroy(&pointIS);
4422: PetscFree4(u, u_t, elemVec, a);
4423: }
4424: DMDestroy(&plex);
4425: DMDestroy(&plexA);
4426: return(0);
4427: }
4429: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF)
4430: {
4431: DMField coordField;
4432: DMLabel depthLabel;
4433: IS facetIS;
4434: PetscInt dim;
4438: DMGetDimension(dm, &dim);
4439: DMPlexGetDepthLabel(dm, &depthLabel);
4440: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
4441: DMGetCoordinateField(dm, &coordField);
4442: DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4443: ISDestroy(&facetIS);
4444: return(0);
4445: }
4447: PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4448: {
4449: PetscDS prob;
4450: PetscInt numBd, bd;
4451: DMField coordField = NULL;
4452: IS facetIS = NULL;
4453: DMLabel depthLabel;
4454: PetscInt dim;
4458: DMGetDS(dm, &prob);
4459: DMPlexGetDepthLabel(dm, &depthLabel);
4460: DMGetDimension(dm, &dim);
4461: DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS);
4462: PetscDSGetNumBoundary(prob, &numBd);
4463: for (bd = 0; bd < numBd; ++bd) {
4464: DMBoundaryConditionType type;
4465: const char *bdLabel;
4466: DMLabel label;
4467: const PetscInt *values;
4468: PetscInt field, numValues;
4469: PetscObject obj;
4470: PetscClassId id;
4472: PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &field, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
4473: PetscDSGetDiscretization(prob, field, &obj);
4474: PetscObjectGetClassId(obj, &id);
4475: if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
4476: if (!facetIS) {
4477: DMLabel depthLabel;
4478: PetscInt dim;
4480: DMPlexGetDepthLabel(dm, &depthLabel);
4481: DMGetDimension(dm, &dim);
4482: DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4483: }
4484: DMGetCoordinateField(dm, &coordField);
4485: DMGetLabel(dm, bdLabel, &label);
4486: DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4487: }
4488: ISDestroy(&facetIS);
4489: return(0);
4490: }
4492: PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscHashFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4493: {
4494: DM_Plex *mesh = (DM_Plex *) dm->data;
4495: const char *name = "Residual";
4496: DM dmAux = NULL;
4497: DM dmGrad = NULL;
4498: DMLabel ghostLabel = NULL;
4499: PetscDS ds = NULL;
4500: PetscDS dsAux = NULL;
4501: PetscSection section = NULL;
4502: PetscBool useFEM = PETSC_FALSE;
4503: PetscBool useFVM = PETSC_FALSE;
4504: PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
4505: PetscFV fvm = NULL;
4506: PetscFVCellGeom *cgeomFVM = NULL;
4507: PetscFVFaceGeom *fgeomFVM = NULL;
4508: DMField coordField = NULL;
4509: Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
4510: PetscScalar *u = NULL, *u_t, *a, *uL, *uR;
4511: IS chunkIS;
4512: const PetscInt *cells;
4513: PetscInt cStart, cEnd, numCells;
4514: PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
4515: PetscInt maxDegree = PETSC_MAX_INT;
4516: PetscQuadrature affineQuad = NULL, *quads = NULL;
4517: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4518: PetscErrorCode ierr;
4521: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4522: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4523: /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
4524: /* FEM+FVM */
4525: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4526: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4527: /* 1: Get sizes from dm and dmAux */
4528: DMGetLocalSection(dm, §ion);
4529: DMGetLabel(dm, "ghost", &ghostLabel);
4530: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds);
4531: PetscDSGetNumFields(ds, &Nf);
4532: PetscDSGetTotalDimension(ds, &totDim);
4533: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4534: if (locA) {
4535: PetscInt subcell;
4536: VecGetDM(locA, &dmAux);
4537: DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell);
4538: DMGetCellDS(dmAux, subcell, &dsAux);
4539: PetscDSGetTotalDimension(dsAux, &totDimAux);
4540: }
4541: /* 2: Get geometric data */
4542: for (f = 0; f < Nf; ++f) {
4543: PetscObject obj;
4544: PetscClassId id;
4545: PetscBool fimp;
4547: PetscDSGetImplicit(ds, f, &fimp);
4548: if (isImplicit != fimp) continue;
4549: PetscDSGetDiscretization(ds, f, &obj);
4550: PetscObjectGetClassId(obj, &id);
4551: if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
4552: if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;}
4553: }
4554: if (useFEM) {
4555: DMGetCoordinateField(dm, &coordField);
4556: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
4557: if (maxDegree <= 1) {
4558: DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
4559: if (affineQuad) {
4560: DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4561: }
4562: } else {
4563: PetscCalloc2(Nf,&quads,Nf,&geoms);
4564: for (f = 0; f < Nf; ++f) {
4565: PetscObject obj;
4566: PetscClassId id;
4567: PetscBool fimp;
4569: PetscDSGetImplicit(ds, f, &fimp);
4570: if (isImplicit != fimp) continue;
4571: PetscDSGetDiscretization(ds, f, &obj);
4572: PetscObjectGetClassId(obj, &id);
4573: if (id == PETSCFE_CLASSID) {
4574: PetscFE fe = (PetscFE) obj;
4576: PetscFEGetQuadrature(fe, &quads[f]);
4577: PetscObjectReference((PetscObject)quads[f]);
4578: DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4579: }
4580: }
4581: }
4582: }
4583: if (useFVM) {
4584: DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);
4585: VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM);
4586: VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
4587: /* Reconstruct and limit cell gradients */
4588: DMPlexGetGradientDM(dm, fvm, &dmGrad);
4589: if (dmGrad) {
4590: DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4591: DMGetGlobalVector(dmGrad, &grad);
4592: DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
4593: /* Communicate gradient values */
4594: DMGetLocalVector(dmGrad, &locGrad);
4595: DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
4596: DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
4597: DMRestoreGlobalVector(dmGrad, &grad);
4598: }
4599: /* Handle non-essential (e.g. outflow) boundary values */
4600: DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);
4601: }
4602: /* Loop over chunks */
4603: if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
4604: numCells = cEnd - cStart;
4605: numChunks = 1;
4606: cellChunkSize = numCells/numChunks;
4607: faceChunkSize = (fEnd - fStart)/numChunks;
4608: numChunks = PetscMin(1,numCells);
4609: for (chunk = 0; chunk < numChunks; ++chunk) {
4610: PetscScalar *elemVec, *fluxL, *fluxR;
4611: PetscReal *vol;
4612: PetscFVFaceGeom *fgeom;
4613: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4614: PetscInt fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face;
4616: /* Extract field coefficients */
4617: if (useFEM) {
4618: ISGetPointSubrange(chunkIS, cS, cE, cells);
4619: DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4620: DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4621: PetscArrayzero(elemVec, numCells*totDim);
4622: }
4623: if (useFVM) {
4624: DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4625: DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4626: DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4627: DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4628: PetscArrayzero(fluxL, numFaces*totDim);
4629: PetscArrayzero(fluxR, numFaces*totDim);
4630: }
4631: /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
4632: /* Loop over fields */
4633: for (f = 0; f < Nf; ++f) {
4634: PetscObject obj;
4635: PetscClassId id;
4636: PetscBool fimp;
4637: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
4639: key.field = f;
4640: PetscDSGetImplicit(ds, f, &fimp);
4641: if (isImplicit != fimp) continue;
4642: PetscDSGetDiscretization(ds, f, &obj);
4643: PetscObjectGetClassId(obj, &id);
4644: if (id == PETSCFE_CLASSID) {
4645: PetscFE fe = (PetscFE) obj;
4646: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4647: PetscFEGeom *chunkGeom = NULL;
4648: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4649: PetscInt Nq, Nb;
4651: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4652: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4653: PetscFEGetDimension(fe, &Nb);
4654: blockSize = Nb;
4655: batchSize = numBlocks * blockSize;
4656: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4657: numChunks = numCells / (numBatches*batchSize);
4658: Ne = numChunks*numBatches*batchSize;
4659: Nr = numCells % (numBatches*batchSize);
4660: offset = numCells - Nr;
4661: /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4662: /* 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) */
4663: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4664: PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec);
4665: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4666: PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4667: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4668: } else if (id == PETSCFV_CLASSID) {
4669: PetscFV fv = (PetscFV) obj;
4671: Ne = numFaces;
4672: /* Riemann solve over faces (need fields at face centroids) */
4673: /* We need to evaluate FE fields at those coordinates */
4674: PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4675: } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
4676: }
4677: /* Loop over domain */
4678: if (useFEM) {
4679: /* Add elemVec to locX */
4680: for (c = cS; c < cE; ++c) {
4681: const PetscInt cell = cells ? cells[c] : c;
4682: const PetscInt cind = c - cStart;
4684: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
4685: if (ghostLabel) {
4686: PetscInt ghostVal;
4688: DMLabelGetValue(ghostLabel,cell,&ghostVal);
4689: if (ghostVal > 0) continue;
4690: }
4691: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4692: }
4693: }
4694: if (useFVM) {
4695: PetscScalar *fa;
4696: PetscInt iface;
4698: VecGetArray(locF, &fa);
4699: for (f = 0; f < Nf; ++f) {
4700: PetscFV fv;
4701: PetscObject obj;
4702: PetscClassId id;
4703: PetscInt foff, pdim;
4705: PetscDSGetDiscretization(ds, f, &obj);
4706: PetscDSGetFieldOffset(ds, f, &foff);
4707: PetscObjectGetClassId(obj, &id);
4708: if (id != PETSCFV_CLASSID) continue;
4709: fv = (PetscFV) obj;
4710: PetscFVGetNumComponents(fv, &pdim);
4711: /* Accumulate fluxes to cells */
4712: for (face = fS, iface = 0; face < fE; ++face) {
4713: const PetscInt *scells;
4714: PetscScalar *fL = NULL, *fR = NULL;
4715: PetscInt ghost, d, nsupp, nchild;
4717: DMLabelGetValue(ghostLabel, face, &ghost);
4718: DMPlexGetSupportSize(dm, face, &nsupp);
4719: DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4720: if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4721: DMPlexGetSupport(dm, face, &scells);
4722: DMLabelGetValue(ghostLabel,scells[0],&ghost);
4723: if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);}
4724: DMLabelGetValue(ghostLabel,scells[1],&ghost);
4725: if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);}
4726: for (d = 0; d < pdim; ++d) {
4727: if (fL) fL[d] -= fluxL[iface*totDim+foff+d];
4728: if (fR) fR[d] += fluxR[iface*totDim+foff+d];
4729: }
4730: ++iface;
4731: }
4732: }
4733: VecRestoreArray(locF, &fa);
4734: }
4735: /* Handle time derivative */
4736: if (locX_t) {
4737: PetscScalar *x_t, *fa;
4739: VecGetArray(locF, &fa);
4740: VecGetArray(locX_t, &x_t);
4741: for (f = 0; f < Nf; ++f) {
4742: PetscFV fv;
4743: PetscObject obj;
4744: PetscClassId id;
4745: PetscInt pdim, d;
4747: PetscDSGetDiscretization(ds, f, &obj);
4748: PetscObjectGetClassId(obj, &id);
4749: if (id != PETSCFV_CLASSID) continue;
4750: fv = (PetscFV) obj;
4751: PetscFVGetNumComponents(fv, &pdim);
4752: for (c = cS; c < cE; ++c) {
4753: const PetscInt cell = cells ? cells[c] : c;
4754: PetscScalar *u_t, *r;
4756: if (ghostLabel) {
4757: PetscInt ghostVal;
4759: DMLabelGetValue(ghostLabel, cell, &ghostVal);
4760: if (ghostVal > 0) continue;
4761: }
4762: DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4763: DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4764: for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4765: }
4766: }
4767: VecRestoreArray(locX_t, &x_t);
4768: VecRestoreArray(locF, &fa);
4769: }
4770: if (useFEM) {
4771: DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4772: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4773: }
4774: if (useFVM) {
4775: DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4776: DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4777: DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4778: DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4779: if (dmGrad) {DMRestoreLocalVector(dmGrad, &locGrad);}
4780: }
4781: }
4782: if (useFEM) {ISDestroy(&chunkIS);}
4783: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
4785: if (useFEM) {
4786: DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);
4788: if (maxDegree <= 1) {
4789: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4790: PetscQuadratureDestroy(&affineQuad);
4791: } else {
4792: for (f = 0; f < Nf; ++f) {
4793: DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4794: PetscQuadratureDestroy(&quads[f]);
4795: }
4796: PetscFree2(quads,geoms);
4797: }
4798: }
4800: /* FEM */
4801: /* 1: Get sizes from dm and dmAux */
4802: /* 2: Get geometric data */
4803: /* 3: Handle boundary values */
4804: /* 4: Loop over domain */
4805: /* Extract coefficients */
4806: /* Loop over fields */
4807: /* Set tiling for FE*/
4808: /* Integrate FE residual to get elemVec */
4809: /* Loop over subdomain */
4810: /* Loop over quad points */
4811: /* Transform coords to real space */
4812: /* Evaluate field and aux fields at point */
4813: /* Evaluate residual at point */
4814: /* Transform residual to real space */
4815: /* Add residual to elemVec */
4816: /* Loop over domain */
4817: /* Add elemVec to locX */
4819: /* FVM */
4820: /* Get geometric data */
4821: /* If using gradients */
4822: /* Compute gradient data */
4823: /* Loop over domain faces */
4824: /* Count computational faces */
4825: /* Reconstruct cell gradient */
4826: /* Loop over domain cells */
4827: /* Limit cell gradients */
4828: /* Handle boundary values */
4829: /* Loop over domain faces */
4830: /* Read out field, centroid, normal, volume for each side of face */
4831: /* Riemann solve over faces */
4832: /* Loop over domain faces */
4833: /* Accumulate fluxes to cells */
4834: /* TODO Change printFEM to printDisc here */
4835: if (mesh->printFEM) {
4836: Vec locFbc;
4837: PetscInt pStart, pEnd, p, maxDof;
4838: PetscScalar *zeroes;
4840: VecDuplicate(locF,&locFbc);
4841: VecCopy(locF,locFbc);
4842: PetscSectionGetChart(section,&pStart,&pEnd);
4843: PetscSectionGetMaxDof(section,&maxDof);
4844: PetscCalloc1(maxDof,&zeroes);
4845: for (p = pStart; p < pEnd; p++) {
4846: VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);
4847: }
4848: PetscFree(zeroes);
4849: DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4850: VecDestroy(&locFbc);
4851: }
4852: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4853: return(0);
4854: }
4856: /*
4857: 1) Allow multiple kernels for BdResidual for hybrid DS
4859: DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux
4861: DONE 3) Change DMGetCellFields() to get different aux data a[] for each side
4862: - I think I just need to replace a[] with the closure from each face
4864: 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before
4865: */
4866: PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscHashFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4867: {
4868: DM_Plex *mesh = (DM_Plex *) dm->data;
4869: const char *name = "Hybrid Residual";
4870: DM dmAux = NULL;
4871: DMLabel ghostLabel = NULL;
4872: PetscDS ds = NULL;
4873: PetscDS dsAux[3] = {NULL, NULL, NULL};
4874: PetscSection section = NULL;
4875: DMField coordField = NULL;
4876: Vec locA;
4877: PetscScalar *u = NULL, *u_t, *a[3];
4878: PetscScalar *elemVec;
4879: IS chunkIS;
4880: const PetscInt *cells;
4881: PetscInt *faces;
4882: PetscInt cStart, cEnd, numCells;
4883: PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
4884: PetscInt maxDegree = PETSC_MAX_INT;
4885: PetscQuadrature affineQuad = NULL, *quads = NULL;
4886: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
4887: PetscErrorCode ierr;
4890: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4891: /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4892: /* FEM */
4893: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4894: /* 1: Get sizes from dm and dmAux */
4895: DMGetSection(dm, §ion);
4896: DMGetLabel(dm, "ghost", &ghostLabel);
4897: DMGetCellDS(dm, cStart, &ds);
4898: PetscDSGetNumFields(ds, &Nf);
4899: PetscDSGetTotalDimension(ds, &totDim);
4900: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4901: if (locA) {
4902: VecGetDM(locA, &dmAux);
4903: DMGetCellDS(dmAux, cStart, &dsAux[2]);
4904: PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
4905: {
4906: const PetscInt *cone;
4907: PetscInt c;
4909: DMPlexGetCone(dm, cStart, &cone);
4910: for (c = 0; c < 2; ++c) {
4911: const PetscInt *support;
4912: PetscInt ssize, s;
4914: DMPlexGetSupport(dm, cone[c], &support);
4915: DMPlexGetSupportSize(dm, cone[c], &ssize);
4916: if (ssize != 2) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[c], cStart, ssize);
4917: if (support[0] == cStart) s = 1;
4918: else if (support[1] == cStart) s = 0;
4919: else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart);
4920: DMGetCellDS(dmAux, support[s], &dsAux[c]);
4921: PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
4922: }
4923: }
4924: }
4925: /* 2: Setup geometric data */
4926: DMGetCoordinateField(dm, &coordField);
4927: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4928: if (maxDegree > 1) {
4929: PetscCalloc2(Nf, &quads, Nf, &geoms);
4930: for (f = 0; f < Nf; ++f) {
4931: PetscFE fe;
4933: PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4934: if (fe) {
4935: PetscFEGetQuadrature(fe, &quads[f]);
4936: PetscObjectReference((PetscObject) quads[f]);
4937: }
4938: }
4939: }
4940: /* Loop over chunks */
4941: numCells = cEnd - cStart;
4942: cellChunkSize = numCells;
4943: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
4944: PetscCalloc1(2*cellChunkSize, &faces);
4945: ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4946: /* Extract field coefficients */
4947: /* NOTE This needs the end cap faces to have identical orientations */
4948: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a[2]);
4949: DMPlexGetHybridAuxFields(dm, dsAux, cellIS, locA, a);
4950: DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);
4951: for (chunk = 0; chunk < numChunks; ++chunk) {
4952: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4954: PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));
4955: /* Get faces */
4956: for (c = cS; c < cE; ++c) {
4957: const PetscInt cell = cells ? cells[c] : c;
4958: const PetscInt *cone;
4959: DMPlexGetCone(dm, cell, &cone);
4960: faces[(c-cS)*2+0] = cone[0];
4961: faces[(c-cS)*2+1] = cone[1];
4962: }
4963: ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
4964: /* Get geometric data */
4965: if (maxDegree <= 1) {
4966: if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
4967: if (affineQuad) {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
4968: } else {
4969: for (f = 0; f < Nf; ++f) {
4970: if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
4971: }
4972: }
4973: /* Loop over fields */
4974: for (f = 0; f < Nf; ++f) {
4975: PetscFE fe;
4976: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f];
4977: PetscFEGeom *chunkGeom = NULL;
4978: PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4979: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
4981: PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4982: if (!fe) continue;
4983: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4984: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4985: PetscFEGetDimension(fe, &Nb);
4986: blockSize = Nb;
4987: batchSize = numBlocks * blockSize;
4988: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4989: numChunks = numCells / (numBatches*batchSize);
4990: Ne = numChunks*numBatches*batchSize;
4991: Nr = numCells % (numBatches*batchSize);
4992: offset = numCells - Nr;
4993: if (f == Nf-1) {
4994: key[2].field = f;
4995: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4996: PetscFEIntegrateHybridResidual(ds, key[2], Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec);
4997: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4998: PetscFEIntegrateHybridResidual(ds, key[2], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[2], &a[2][offset*totDimAux[2]], t, &elemVec[offset*totDim]);
4999: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
5000: } else {
5001: key[0].field = f;
5002: key[1].field = f;
5003: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5004: PetscFEIntegrateHybridResidual(ds, key[0], Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec);
5005: PetscFEIntegrateHybridResidual(ds, key[1], Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec);
5006: PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
5007: PetscFEIntegrateHybridResidual(ds, key[0], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[0], &a[0][offset*totDimAux[0]], t, &elemVec[offset*totDim]);
5008: PetscFEIntegrateHybridResidual(ds, key[1], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[1], &a[1][offset*totDimAux[1]], t, &elemVec[offset*totDim]);
5009: PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
5010: }
5011: }
5012: /* Add elemVec to locX */
5013: for (c = cS; c < cE; ++c) {
5014: const PetscInt cell = cells ? cells[c] : c;
5015: const PetscInt cind = c - cStart;
5017: if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
5018: if (ghostLabel) {
5019: PetscInt ghostVal;
5021: DMLabelGetValue(ghostLabel,cell,&ghostVal);
5022: if (ghostVal > 0) continue;
5023: }
5024: DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
5025: }
5026: }
5027: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a[2]);
5028: DMPlexRestoreHybridAuxFields(dm, dsAux, cellIS, locA, a);
5029: DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
5030: PetscFree(faces);
5031: ISDestroy(&chunkIS);
5032: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5033: if (maxDegree <= 1) {
5034: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5035: PetscQuadratureDestroy(&affineQuad);
5036: } else {
5037: for (f = 0; f < Nf; ++f) {
5038: if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);}
5039: if (quads) {PetscQuadratureDestroy(&quads[f]);}
5040: }
5041: PetscFree2(quads,geoms);
5042: }
5043: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
5044: return(0);
5045: }
5047: 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)
5048: {
5049: DM_Plex *mesh = (DM_Plex *) dm->data;
5050: DM plex = NULL, plexA = NULL, tdm;
5051: DMEnclosureType encAux;
5052: PetscDS prob, probAux = NULL;
5053: PetscSection section, sectionAux = NULL;
5054: PetscSection globalSection, subSection = NULL;
5055: Vec locA = NULL, tv;
5056: PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
5057: PetscInt v;
5058: PetscInt Nf, totDim, totDimAux = 0;
5059: PetscBool isMatISP, transform;
5060: PetscErrorCode ierr;
5063: DMConvert(dm, DMPLEX, &plex);
5064: DMHasBasisTransform(dm, &transform);
5065: DMGetBasisTransformDM_Internal(dm, &tdm);
5066: DMGetBasisTransformVec_Internal(dm, &tv);
5067: DMGetLocalSection(dm, §ion);
5068: DMGetDS(dm, &prob);
5069: PetscDSGetNumFields(prob, &Nf);
5070: PetscDSGetTotalDimension(prob, &totDim);
5071: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
5072: if (locA) {
5073: DM dmAux;
5075: VecGetDM(locA, &dmAux);
5076: DMGetEnclosureRelation(dmAux, dm, &encAux);
5077: DMConvert(dmAux, DMPLEX, &plexA);
5078: DMGetDS(plexA, &probAux);
5079: PetscDSGetTotalDimension(probAux, &totDimAux);
5080: DMGetLocalSection(plexA, §ionAux);
5081: }
5083: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5084: DMGetGlobalSection(dm, &globalSection);
5085: if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5086: for (v = 0; v < numValues; ++v) {
5087: PetscFEGeom *fgeom;
5088: PetscInt maxDegree;
5089: PetscQuadrature qGeom = NULL;
5090: IS pointIS;
5091: const PetscInt *points;
5092: PetscInt numFaces, face, Nq;
5094: DMLabelGetStratumIS(label, values[v], &pointIS);
5095: if (!pointIS) continue; /* No points with that id on this process */
5096: {
5097: IS isectIS;
5099: /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
5100: ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
5101: ISDestroy(&pointIS);
5102: pointIS = isectIS;
5103: }
5104: ISGetLocalSize(pointIS, &numFaces);
5105: ISGetIndices(pointIS, &points);
5106: PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);
5107: DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
5108: if (maxDegree <= 1) {
5109: DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
5110: }
5111: if (!qGeom) {
5112: PetscFE fe;
5114: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5115: PetscFEGetFaceQuadrature(fe, &qGeom);
5116: PetscObjectReference((PetscObject)qGeom);
5117: }
5118: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5119: DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5120: for (face = 0; face < numFaces; ++face) {
5121: const PetscInt point = points[face], *support;
5122: PetscScalar *x = NULL;
5123: PetscInt i;
5125: DMPlexGetSupport(dm, point, &support);
5126: DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5127: for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
5128: DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5129: if (locX_t) {
5130: DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5131: for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
5132: DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5133: }
5134: if (locA) {
5135: PetscInt subp;
5136: DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5137: DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5138: for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
5139: DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5140: }
5141: }
5142: PetscArrayzero(elemMat, numFaces*totDim*totDim);
5143: {
5144: PetscFE fe;
5145: PetscInt Nb;
5146: /* Conforming batches */
5147: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5148: /* Remainder */
5149: PetscFEGeom *chunkGeom = NULL;
5150: PetscInt fieldJ, Nr, offset;
5152: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5153: PetscFEGetDimension(fe, &Nb);
5154: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5155: blockSize = Nb;
5156: batchSize = numBlocks * blockSize;
5157: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5158: numChunks = numFaces / (numBatches*batchSize);
5159: Ne = numChunks*numBatches*batchSize;
5160: Nr = numFaces % (numBatches*batchSize);
5161: offset = numFaces - Nr;
5162: PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
5163: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5164: PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5165: }
5166: PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
5167: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5168: 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]);
5169: }
5170: PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
5171: }
5172: for (face = 0; face < numFaces; ++face) {
5173: const PetscInt point = points[face], *support;
5175: /* Transform to global basis before insertion in Jacobian */
5176: DMPlexGetSupport(plex, point, &support);
5177: if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);}
5178: if (mesh->printFEM > 1) {DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);}
5179: if (!isMatISP) {
5180: DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5181: } else {
5182: Mat lJ;
5184: MatISGetLocalMat(JacP, &lJ);
5185: DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5186: }
5187: }
5188: DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5189: PetscQuadratureDestroy(&qGeom);
5190: ISRestoreIndices(pointIS, &points);
5191: ISDestroy(&pointIS);
5192: PetscFree4(u, u_t, elemMat, a);
5193: }
5194: if (plex) {DMDestroy(&plex);}
5195: if (plexA) {DMDestroy(&plexA);}
5196: return(0);
5197: }
5199: 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)
5200: {
5201: DMField coordField;
5202: DMLabel depthLabel;
5203: IS facetIS;
5204: PetscInt dim;
5208: DMGetDimension(dm, &dim);
5209: DMPlexGetDepthLabel(dm, &depthLabel);
5210: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5211: DMGetCoordinateField(dm, &coordField);
5212: DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5213: ISDestroy(&facetIS);
5214: return(0);
5215: }
5217: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5218: {
5219: PetscDS prob;
5220: PetscInt dim, numBd, bd;
5221: DMLabel depthLabel;
5222: DMField coordField = NULL;
5223: IS facetIS;
5224: PetscErrorCode ierr;
5227: DMGetDS(dm, &prob);
5228: DMPlexGetDepthLabel(dm, &depthLabel);
5229: DMGetDimension(dm, &dim);
5230: DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5231: PetscDSGetNumBoundary(prob, &numBd);
5232: DMGetCoordinateField(dm, &coordField);
5233: for (bd = 0; bd < numBd; ++bd) {
5234: DMBoundaryConditionType type;
5235: const char *bdLabel;
5236: DMLabel label;
5237: const PetscInt *values;
5238: PetscInt fieldI, numValues;
5239: PetscObject obj;
5240: PetscClassId id;
5242: PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &fieldI, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
5243: PetscDSGetDiscretization(prob, fieldI, &obj);
5244: PetscObjectGetClassId(obj, &id);
5245: if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
5246: DMGetLabel(dm, bdLabel, &label);
5247: DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5248: }
5249: ISDestroy(&facetIS);
5250: return(0);
5251: }
5253: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscHashFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user)
5254: {
5255: DM_Plex *mesh = (DM_Plex *) dm->data;
5256: const char *name = "Jacobian";
5257: DM dmAux, plex, tdm;
5258: DMEnclosureType encAux;
5259: Vec A, tv;
5260: DMField coordField;
5261: PetscDS prob, probAux = NULL;
5262: PetscSection section, globalSection, subSection, sectionAux;
5263: PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5264: const PetscInt *cells;
5265: PetscInt Nf, fieldI, fieldJ;
5266: PetscInt totDim, totDimAux, cStart, cEnd, numCells, c;
5267: PetscBool isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform;
5268: PetscErrorCode ierr;
5271: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5272: ISGetLocalSize(cellIS, &numCells);
5273: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5274: DMHasBasisTransform(dm, &transform);
5275: DMGetBasisTransformDM_Internal(dm, &tdm);
5276: DMGetBasisTransformVec_Internal(dm, &tv);
5277: DMGetLocalSection(dm, §ion);
5278: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5279: DMGetGlobalSection(dm, &globalSection);
5280: if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5281: ISGetLocalSize(cellIS, &numCells);
5282: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5283: DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5284: PetscDSGetNumFields(prob, &Nf);
5285: PetscDSGetTotalDimension(prob, &totDim);
5286: PetscDSHasJacobian(prob, &hasJac);
5287: PetscDSHasJacobianPreconditioner(prob, &hasPrec);
5288: /* user passed in the same matrix, avoid double contributions and
5289: only assemble the Jacobian */
5290: if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
5291: PetscDSHasDynamicJacobian(prob, &hasDyn);
5292: hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5293: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
5294: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
5295: if (dmAux) {
5296: DMGetEnclosureRelation(dmAux, dm, &encAux);
5297: DMConvert(dmAux, DMPLEX, &plex);
5298: DMGetLocalSection(plex, §ionAux);
5299: DMGetDS(dmAux, &probAux);
5300: PetscDSGetTotalDimension(probAux, &totDimAux);
5301: }
5302: 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);
5303: if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
5304: DMGetCoordinateField(dm, &coordField);
5305: for (c = cStart; c < cEnd; ++c) {
5306: const PetscInt cell = cells ? cells[c] : c;
5307: const PetscInt cind = c - cStart;
5308: PetscScalar *x = NULL, *x_t = NULL;
5309: PetscInt i;
5311: DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5312: for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5313: DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5314: if (X_t) {
5315: DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5316: for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5317: DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5318: }
5319: if (dmAux) {
5320: PetscInt subcell;
5321: DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5322: DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5323: for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5324: DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5325: }
5326: }
5327: if (hasJac) {PetscArrayzero(elemMat, numCells*totDim*totDim);}
5328: if (hasPrec) {PetscArrayzero(elemMatP, numCells*totDim*totDim);}
5329: if (hasDyn) {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5330: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5331: PetscClassId id;
5332: PetscFE fe;
5333: PetscQuadrature qGeom = NULL;
5334: PetscInt Nb;
5335: /* Conforming batches */
5336: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5337: /* Remainder */
5338: PetscInt Nr, offset, Nq;
5339: PetscInt maxDegree;
5340: PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
5342: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5343: PetscObjectGetClassId((PetscObject) fe, &id);
5344: if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;}
5345: PetscFEGetDimension(fe, &Nb);
5346: PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5347: DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
5348: if (maxDegree <= 1) {
5349: DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);
5350: }
5351: if (!qGeom) {
5352: PetscFEGetQuadrature(fe,&qGeom);
5353: PetscObjectReference((PetscObject)qGeom);
5354: }
5355: PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5356: DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5357: blockSize = Nb;
5358: batchSize = numBlocks * blockSize;
5359: PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5360: numChunks = numCells / (numBatches*batchSize);
5361: Ne = numChunks*numBatches*batchSize;
5362: Nr = numCells % (numBatches*batchSize);
5363: offset = numCells - Nr;
5364: PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
5365: PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);
5366: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5367: key.field = fieldI*Nf+fieldJ;
5368: if (hasJac) {
5369: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5370: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5371: }
5372: if (hasPrec) {
5373: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5374: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5375: }
5376: if (hasDyn) {
5377: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5378: PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);
5379: }
5380: }
5381: PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);
5382: PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);
5383: DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5384: PetscQuadratureDestroy(&qGeom);
5385: }
5386: /* Add contribution from X_t */
5387: if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
5388: if (hasFV) {
5389: PetscClassId id;
5390: PetscFV fv;
5391: PetscInt offsetI, NcI, NbI = 1, fc, f;
5393: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5394: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
5395: PetscDSGetFieldOffset(prob, fieldI, &offsetI);
5396: PetscObjectGetClassId((PetscObject) fv, &id);
5397: if (id != PETSCFV_CLASSID) continue;
5398: /* Put in the identity */
5399: PetscFVGetNumComponents(fv, &NcI);
5400: for (c = cStart; c < cEnd; ++c) {
5401: const PetscInt cind = c - cStart;
5402: const PetscInt eOffset = cind*totDim*totDim;
5403: for (fc = 0; fc < NcI; ++fc) {
5404: for (f = 0; f < NbI; ++f) {
5405: const PetscInt i = offsetI + f*NcI+fc;
5406: if (hasPrec) {
5407: if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;}
5408: elemMatP[eOffset+i*totDim+i] = 1.0;
5409: } else {elemMat[eOffset+i*totDim+i] = 1.0;}
5410: }
5411: }
5412: }
5413: }
5414: /* No allocated space for FV stuff, so ignore the zero entries */
5415: MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);
5416: }
5417: /* Insert values into matrix */
5418: isMatIS = PETSC_FALSE;
5419: if (hasPrec && hasJac) {
5420: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);
5421: }
5422: if (isMatIS && !subSection) {
5423: DMPlexGetSubdomainSection(dm, &subSection);
5424: }
5425: for (c = cStart; c < cEnd; ++c) {
5426: const PetscInt cell = cells ? cells[c] : c;
5427: const PetscInt cind = c - cStart;
5429: /* Transform to global basis before insertion in Jacobian */
5430: if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);}
5431: if (hasPrec) {
5432: if (hasJac) {
5433: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5434: if (!isMatIS) {
5435: DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5436: } else {
5437: Mat lJ;
5439: MatISGetLocalMat(Jac,&lJ);
5440: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5441: }
5442: }
5443: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5444: if (!isMatISP) {
5445: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5446: } else {
5447: Mat lJ;
5449: MatISGetLocalMat(JacP,&lJ);
5450: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5451: }
5452: } else {
5453: if (hasJac) {
5454: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5455: if (!isMatISP) {
5456: DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5457: } else {
5458: Mat lJ;
5460: MatISGetLocalMat(JacP,&lJ);
5461: DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5462: }
5463: }
5464: }
5465: }
5466: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5467: if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
5468: PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);
5469: if (dmAux) {
5470: PetscFree(a);
5471: DMDestroy(&plex);
5472: }
5473: /* Compute boundary integrals */
5474: DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5475: /* Assemble matrix */
5476: if (hasJac && hasPrec) {
5477: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5478: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5479: }
5480: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5481: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5482: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5483: return(0);
5484: }
5486: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5487: {
5488: DM_Plex *mesh = (DM_Plex *) dm->data;
5489: const char *name = "Hybrid Jacobian";
5490: DM dmAux = NULL;
5491: DM plex = NULL;
5492: DM plexA = NULL;
5493: DMLabel ghostLabel = NULL;
5494: PetscDS prob = NULL;
5495: PetscDS probAux = NULL;
5496: PetscSection section = NULL;
5497: DMField coordField = NULL;
5498: Vec locA;
5499: PetscScalar *u = NULL, *u_t, *a = NULL;
5500: PetscScalar *elemMat, *elemMatP;
5501: PetscSection globalSection, subSection, sectionAux;
5502: IS chunkIS;
5503: const PetscInt *cells;
5504: PetscInt *faces;
5505: PetscInt cStart, cEnd, numCells;
5506: PetscInt Nf, fieldI, fieldJ, totDim, totDimAux, numChunks, cellChunkSize, chunk;
5507: PetscInt maxDegree = PETSC_MAX_INT;
5508: PetscQuadrature affineQuad = NULL, *quads = NULL;
5509: PetscFEGeom *affineGeom = NULL, **geoms = NULL;
5510: PetscBool isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec;
5511: PetscErrorCode ierr;
5514: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5515: ISGetLocalSize(cellIS, &numCells);
5516: ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5517: DMConvert(dm, DMPLEX, &plex);
5518: DMGetSection(dm, §ion);
5519: DMGetGlobalSection(dm, &globalSection);
5520: DMGetLabel(dm, "ghost", &ghostLabel);
5521: DMGetCellDS(dm, cStart, &prob);
5522: PetscDSGetNumFields(prob, &Nf);
5523: PetscDSGetTotalDimension(prob, &totDim);
5524: PetscDSHasBdJacobian(prob, &hasBdJac);
5525: PetscDSHasBdJacobianPreconditioner(prob, &hasBdPrec);
5526: PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5527: if (isMatISP) {DMPlexGetSubdomainSection(plex, &subSection);}
5528: if (hasBdPrec && hasBdJac) {PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);}
5529: if (isMatIS && !subSection) {DMPlexGetSubdomainSection(plex, &subSection);}
5530: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
5531: if (locA) {
5532: VecGetDM(locA, &dmAux);
5533: DMConvert(dmAux, DMPLEX, &plexA);
5534: DMGetSection(dmAux, §ionAux);
5535: DMGetCellDS(dmAux, cStart, &probAux);
5536: PetscDSGetTotalDimension(probAux, &totDimAux);
5537: }
5538: DMGetCoordinateField(dm, &coordField);
5539: DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5540: if (maxDegree > 1) {
5541: PetscInt f;
5542: PetscCalloc2(Nf,&quads,Nf,&geoms);
5543: for (f = 0; f < Nf; ++f) {
5544: PetscFE fe;
5546: PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
5547: if (fe) {
5548: PetscFEGetQuadrature(fe, &quads[f]);
5549: PetscObjectReference((PetscObject) quads[f]);
5550: }
5551: }
5552: }
5553: cellChunkSize = numCells;
5554: numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
5555: PetscCalloc1(2*cellChunkSize, &faces);
5556: ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5557: DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5558: DMGetWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5559: DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5560: for (chunk = 0; chunk < numChunks; ++chunk) {
5561: PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
5563: if (hasBdJac) {PetscMemzero(elemMat, numCells*totDim*totDim * sizeof(PetscScalar));}
5564: if (hasBdPrec) {PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));}
5565: /* Get faces */
5566: for (c = cS; c < cE; ++c) {
5567: const PetscInt cell = cells ? cells[c] : c;
5568: const PetscInt *cone;
5569: DMPlexGetCone(plex, cell, &cone);
5570: faces[(c-cS)*2+0] = cone[0];
5571: faces[(c-cS)*2+1] = cone[1];
5572: }
5573: ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
5574: if (maxDegree <= 1) {
5575: if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
5576: if (affineQuad) {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
5577: } else {
5578: PetscInt f;
5579: for (f = 0; f < Nf; ++f) {
5580: if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
5581: }
5582: }
5584: for (fieldI = 0; fieldI < Nf; ++fieldI) {
5585: PetscFE feI;
5586: PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI];
5587: PetscFEGeom *chunkGeom = NULL, *remGeom = NULL;
5588: PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5589: PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
5591: PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &feI);
5592: if (!feI) continue;
5593: PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5594: PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5595: PetscFEGetDimension(feI, &Nb);
5596: blockSize = Nb;
5597: batchSize = numBlocks * blockSize;
5598: PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5599: numChunks = numCells / (numBatches*batchSize);
5600: Ne = numChunks*numBatches*batchSize;
5601: Nr = numCells % (numBatches*batchSize);
5602: offset = numCells - Nr;
5603: PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5604: PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
5605: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5606: PetscFE feJ;
5608: PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &feJ);
5609: if (!feJ) continue;
5610: if (hasBdJac) {
5611: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5612: 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]);
5613: }
5614: if (hasBdPrec) {
5615: PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5616: 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]);
5617: }
5618: }
5619: PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5620: PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5621: }
5622: /* Insert values into matrix */
5623: for (c = cS; c < cE; ++c) {
5624: const PetscInt cell = cells ? cells[c] : c;
5625: const PetscInt cind = c - cS;
5627: if (hasBdPrec) {
5628: if (hasBdJac) {
5629: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5630: if (!isMatIS) {
5631: DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5632: } else {
5633: Mat lJ;
5635: MatISGetLocalMat(Jac,&lJ);
5636: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5637: }
5638: }
5639: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5640: if (!isMatISP) {
5641: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5642: } else {
5643: Mat lJ;
5645: MatISGetLocalMat(JacP,&lJ);
5646: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5647: }
5648: } else if (hasBdJac) {
5649: if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5650: if (!isMatISP) {
5651: DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5652: } else {
5653: Mat lJ;
5655: MatISGetLocalMat(JacP,&lJ);
5656: DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5657: }
5658: }
5659: }
5660: }
5661: DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5662: DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5663: DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5664: PetscFree(faces);
5665: ISDestroy(&chunkIS);
5666: ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5667: if (maxDegree <= 1) {
5668: DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5669: PetscQuadratureDestroy(&affineQuad);
5670: } else {
5671: PetscInt f;
5672: for (f = 0; f < Nf; ++f) {
5673: if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);}
5674: if (quads) {PetscQuadratureDestroy(&quads[f]);}
5675: }
5676: PetscFree2(quads,geoms);
5677: }
5678: if (dmAux) {DMDestroy(&plexA);}
5679: DMDestroy(&plex);
5680: /* Assemble matrix */
5681: if (hasBdJac && hasBdPrec) {
5682: MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5683: MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5684: }
5685: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5686: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5687: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5688: return(0);
5689: }