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