Actual source code: plexfem.c
petsc-dev 2014-02-02
1: #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/
3: #include <petscfe.h>
7: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
8: {
9: DM_Plex *mesh = (DM_Plex*) dm->data;
14: *scale = mesh->scale[unit];
15: return(0);
16: }
20: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
21: {
22: DM_Plex *mesh = (DM_Plex*) dm->data;
26: mesh->scale[unit] = scale;
27: return(0);
28: }
30: PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
31: {
32: switch (i) {
33: case 0:
34: switch (j) {
35: case 0: return 0;
36: case 1:
37: switch (k) {
38: case 0: return 0;
39: case 1: return 0;
40: case 2: return 1;
41: }
42: case 2:
43: switch (k) {
44: case 0: return 0;
45: case 1: return -1;
46: case 2: return 0;
47: }
48: }
49: case 1:
50: switch (j) {
51: case 0:
52: switch (k) {
53: case 0: return 0;
54: case 1: return 0;
55: case 2: return -1;
56: }
57: case 1: return 0;
58: case 2:
59: switch (k) {
60: case 0: return 1;
61: case 1: return 0;
62: case 2: return 0;
63: }
64: }
65: case 2:
66: switch (j) {
67: case 0:
68: switch (k) {
69: case 0: return 0;
70: case 1: return 1;
71: case 2: return 0;
72: }
73: case 1:
74: switch (k) {
75: case 0: return -1;
76: case 1: return 0;
77: case 2: return 0;
78: }
79: case 2: return 0;
80: }
81: }
82: return 0;
83: }
87: /*@C
88: DMPlexCreateRigidBody - create rigid body modes from coordinates
90: Collective on DM
92: Input Arguments:
93: + dm - the DM
94: . section - the local section associated with the rigid field, or NULL for the default section
95: - globalSection - the global section associated with the rigid field, or NULL for the default section
97: Output Argument:
98: . sp - the null space
100: Note: This is necessary to take account of Dirichlet conditions on the displacements
102: Level: advanced
104: .seealso: MatNullSpaceCreate()
105: @*/
106: PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
107: {
108: MPI_Comm comm;
109: Vec coordinates, localMode, mode[6];
110: PetscSection coordSection;
111: PetscScalar *coords;
112: PetscInt dim, vStart, vEnd, v, n, m, d, i, j;
116: PetscObjectGetComm((PetscObject)dm,&comm);
117: DMPlexGetDimension(dm, &dim);
118: if (dim == 1) {
119: MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
120: return(0);
121: }
122: if (!section) {DMGetDefaultSection(dm, §ion);}
123: if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
124: PetscSectionGetConstrainedStorageSize(globalSection, &n);
125: DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
126: DMGetCoordinateSection(dm, &coordSection);
127: DMGetCoordinatesLocal(dm, &coordinates);
128: m = (dim*(dim+1))/2;
129: VecCreate(comm, &mode[0]);
130: VecSetSizes(mode[0], n, PETSC_DETERMINE);
131: VecSetUp(mode[0]);
132: for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
133: /* Assume P1 */
134: DMGetLocalVector(dm, &localMode);
135: for (d = 0; d < dim; ++d) {
136: PetscScalar values[3] = {0.0, 0.0, 0.0};
138: values[d] = 1.0;
139: VecSet(localMode, 0.0);
140: for (v = vStart; v < vEnd; ++v) {
141: DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);
142: }
143: DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);
144: DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);
145: }
146: VecGetArray(coordinates, &coords);
147: for (d = dim; d < dim*(dim+1)/2; ++d) {
148: PetscInt i, j, k = dim > 2 ? d - dim : d;
150: VecSet(localMode, 0.0);
151: for (v = vStart; v < vEnd; ++v) {
152: PetscScalar values[3] = {0.0, 0.0, 0.0};
153: PetscInt off;
155: PetscSectionGetOffset(coordSection, v, &off);
156: for (i = 0; i < dim; ++i) {
157: for (j = 0; j < dim; ++j) {
158: values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
159: }
160: }
161: DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);
162: }
163: DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);
164: DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);
165: }
166: VecRestoreArray(coordinates, &coords);
167: DMRestoreLocalVector(dm, &localMode);
168: for (i = 0; i < dim; ++i) {VecNormalize(mode[i], NULL);}
169: /* Orthonormalize system */
170: for (i = dim; i < m; ++i) {
171: PetscScalar dots[6];
173: VecMDot(mode[i], i, mode, dots);
174: for (j = 0; j < i; ++j) dots[j] *= -1.0;
175: VecMAXPY(mode[i], i, dots, mode);
176: VecNormalize(mode[i], NULL);
177: }
178: MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
179: for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
180: return(0);
181: }
185: PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
186: {
187: PetscDualSpace *sp;
188: PetscSection section;
189: PetscScalar *values;
190: PetscReal *v0, *J, detJ;
191: PetscInt numFields, numComp, dim, spDim, totDim = 0, numValues, cStart, cEnd, c, f, d, v;
192: PetscErrorCode ierr;
195: DMGetDefaultSection(dm, §ion);
196: PetscSectionGetNumFields(section, &numFields);
197: PetscMalloc1(numFields, &sp);
198: for (f = 0; f < numFields; ++f) {
199: PetscFEGetDualSpace(fe[f], &sp[f]);
200: PetscFEGetNumComponents(fe[f], &numComp);
201: PetscDualSpaceGetDimension(sp[f], &spDim);
202: totDim += spDim*numComp;
203: }
204: DMPlexGetDimension(dm, &dim);
205: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
206: DMPlexVecGetClosure(dm, section, localX, cStart, &numValues, NULL);
207: if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section cell closure size %d != dual space dimension %d", numValues, totDim);
208: DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);
209: PetscMalloc2(dim,&v0,dim*dim,&J);
210: for (c = cStart; c < cEnd; ++c) {
211: PetscCellGeometry geom;
213: DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);
214: geom.v0 = v0;
215: geom.J = J;
216: geom.detJ = &detJ;
217: for (f = 0, v = 0; f < numFields; ++f) {
218: void * const ctx = ctxs ? ctxs[f] : NULL;
219: PetscFEGetNumComponents(fe[f], &numComp);
220: PetscDualSpaceGetDimension(sp[f], &spDim);
221: for (d = 0; d < spDim; ++d) {
222: PetscDualSpaceApply(sp[f], d, geom, numComp, funcs[f], ctx, &values[v]);
223: v += numComp;
224: }
225: }
226: DMPlexVecSetClosure(dm, section, localX, c, values, mode);
227: }
228: DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);
229: PetscFree2(v0,J);
230: PetscFree(sp);
231: return(0);
232: }
236: /*@C
237: DMPlexProjectFunction - This projects the given function into the function space provided.
239: Input Parameters:
240: + dm - The DM
241: . fe - The PetscFE associated with the field
242: . funcs - The coordinate functions to evaluate, one per field
243: . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
244: - mode - The insertion mode for values
246: Output Parameter:
247: . X - vector
249: Level: developer
251: .seealso: DMPlexComputeL2Diff()
252: @*/
253: PetscErrorCode DMPlexProjectFunction(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
254: {
255: Vec localX;
260: DMGetLocalVector(dm, &localX);
261: DMPlexProjectFunctionLocal(dm, fe, funcs, ctxs, mode, localX);
262: DMLocalToGlobalBegin(dm, localX, mode, X);
263: DMLocalToGlobalEnd(dm, localX, mode, X);
264: DMRestoreLocalVector(dm, &localX);
265: return(0);
266: }
270: /*@C
271: DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
273: Input Parameters:
274: + dm - The DM
275: . fe - The PetscFE object for each field
276: . funcs - The functions to evaluate for each field component
277: . ctxs - Optional array of contexts to pass to each function, or NULL.
278: - X - The coefficient vector u_h
280: Output Parameter:
281: . diff - The diff ||u - u_h||_2
283: Level: developer
285: .seealso: DMPlexProjectFunction()
286: @*/
287: PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
288: {
289: const PetscInt debug = 0;
290: PetscSection section;
291: PetscQuadrature quad;
292: Vec localX;
293: PetscScalar *funcVal;
294: PetscReal *coords, *v0, *J, *invJ, detJ;
295: PetscReal localDiff = 0.0;
296: PetscInt dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
297: PetscErrorCode ierr;
300: DMPlexGetDimension(dm, &dim);
301: DMGetDefaultSection(dm, §ion);
302: PetscSectionGetNumFields(section, &numFields);
303: DMGetLocalVector(dm, &localX);
304: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
305: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
306: for (field = 0; field < numFields; ++field) {
307: PetscInt Nc;
309: PetscFEGetNumComponents(fe[field], &Nc);
310: numComponents += Nc;
311: }
312: DMPlexProjectFunctionLocal(dm, fe, funcs, ctxs, INSERT_BC_VALUES, localX);
313: PetscMalloc5(numComponents,&funcVal,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);
314: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
315: PetscFEGetQuadrature(fe[0], &quad);
316: for (c = cStart; c < cEnd; ++c) {
317: PetscScalar *x = NULL;
318: PetscReal elemDiff = 0.0;
320: DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
321: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
322: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
324: for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
325: void * const ctx = ctxs ? ctxs[field] : NULL;
326: const PetscInt numQuadPoints = quad.numPoints;
327: const PetscReal *quadPoints = quad.points;
328: const PetscReal *quadWeights = quad.weights;
329: PetscReal *basis;
330: PetscInt numBasisFuncs, numBasisComps, q, d, e, fc, f;
332: PetscFEGetDimension(fe[field], &numBasisFuncs);
333: PetscFEGetNumComponents(fe[field], &numBasisComps);
334: PetscFEGetDefaultTabulation(fe[field], &basis, NULL, NULL);
335: if (debug) {
336: char title[1024];
337: PetscSNPrintf(title, 1023, "Solution for Field %d", field);
338: DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);
339: }
340: for (q = 0; q < numQuadPoints; ++q) {
341: for (d = 0; d < dim; d++) {
342: coords[d] = v0[d];
343: for (e = 0; e < dim; e++) {
344: coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
345: }
346: }
347: (*funcs[field])(coords, funcVal, ctx);
348: for (fc = 0; fc < numBasisComps; ++fc) {
349: PetscScalar interpolant = 0.0;
351: for (f = 0; f < numBasisFuncs; ++f) {
352: const PetscInt fidx = f*numBasisComps+fc;
353: interpolant += x[fieldOffset+fidx]*basis[q*numBasisFuncs*numBasisComps+fidx];
354: }
355: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);}
356: elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
357: }
358: }
359: comp += numBasisComps;
360: fieldOffset += numBasisFuncs*numBasisComps;
361: }
362: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
363: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);}
364: localDiff += elemDiff;
365: }
366: PetscFree5(funcVal,coords,v0,J,invJ);
367: DMRestoreLocalVector(dm, &localX);
368: MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));
369: *diff = PetscSqrtReal(*diff);
370: return(0);
371: }
375: /*@C
376: DMPlexComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
378: Input Parameters:
379: + dm - The DM
380: . fe - The PetscFE object for each field
381: . funcs - The gradient functions to evaluate for each field component
382: . ctxs - Optional array of contexts to pass to each function, or NULL.
383: . X - The coefficient vector u_h
384: - n - The vector to project along
386: Output Parameter:
387: . diff - The diff ||(grad u - grad u_h) . n||_2
389: Level: developer
391: .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff()
392: @*/
393: PetscErrorCode DMPlexComputeL2GradientDiff(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
394: {
395: const PetscInt debug = 0;
396: PetscSection section;
397: PetscQuadrature quad;
398: Vec localX;
399: PetscScalar *funcVal, *interpolantVec;
400: PetscReal *coords, *realSpaceDer, *v0, *J, *invJ, detJ;
401: PetscReal localDiff = 0.0;
402: PetscInt dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
403: PetscErrorCode ierr;
406: DMPlexGetDimension(dm, &dim);
407: DMGetDefaultSection(dm, §ion);
408: PetscSectionGetNumFields(section, &numFields);
409: DMGetLocalVector(dm, &localX);
410: DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
411: DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
412: for (field = 0; field < numFields; ++field) {
413: PetscInt Nc;
415: PetscFEGetNumComponents(fe[field], &Nc);
416: numComponents += Nc;
417: }
418: /* DMPlexProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
419: PetscMalloc7(numComponents,&funcVal,dim,&coords,dim,&realSpaceDer,dim,&v0,dim*dim,&J,dim*dim,&invJ,dim,&interpolantVec);
420: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
421: PetscFEGetQuadrature(fe[0], &quad);
422: for (c = cStart; c < cEnd; ++c) {
423: PetscScalar *x = NULL;
424: PetscReal elemDiff = 0.0;
426: DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
427: if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
428: DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);
430: for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
431: void * const ctx = ctxs ? ctxs[field] : NULL;
432: const PetscInt numQuadPoints = quad.numPoints;
433: const PetscReal *quadPoints = quad.points;
434: const PetscReal *quadWeights = quad.weights;
435: PetscReal *basisDer;
436: PetscInt Nb, Ncomp, q, d, e, fc, f, g;
438: PetscFEGetDimension(fe[field], &Nb);
439: PetscFEGetNumComponents(fe[field], &Ncomp);
440: PetscFEGetDefaultTabulation(fe[field], NULL, &basisDer, NULL);
441: if (debug) {
442: char title[1024];
443: PetscSNPrintf(title, 1023, "Solution for Field %d", field);
444: DMPrintCellVector(c, title, Nb*Ncomp, &x[fieldOffset]);
445: }
446: for (q = 0; q < numQuadPoints; ++q) {
447: for (d = 0; d < dim; d++) {
448: coords[d] = v0[d];
449: for (e = 0; e < dim; e++) {
450: coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
451: }
452: }
453: (*funcs[field])(coords, n, funcVal, ctx);
454: for (fc = 0; fc < Ncomp; ++fc) {
455: PetscScalar interpolant = 0.0;
457: for (d = 0; d < dim; ++d) interpolantVec[d] = 0.0;
458: for (f = 0; f < Nb; ++f) {
459: const PetscInt fidx = f*Ncomp+fc;
461: for (d = 0; d < dim; ++d) {
462: realSpaceDer[d] = 0.0;
463: for (g = 0; g < dim; ++g) {
464: realSpaceDer[d] += invJ[g*dim+d]*basisDer[(q*Nb*Ncomp+fidx)*dim+g];
465: }
466: interpolantVec[d] += x[fieldOffset+fidx]*realSpaceDer[d];
467: }
468: }
469: for (d = 0; d < dim; ++d) interpolant += interpolantVec[d]*n[d];
470: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);}
471: elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
472: }
473: }
474: comp += Ncomp;
475: fieldOffset += Nb*Ncomp;
476: }
477: DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
478: if (debug) {PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);}
479: localDiff += elemDiff;
480: }
481: PetscFree7(funcVal,coords,realSpaceDer,v0,J,invJ,interpolantVec);
482: DMRestoreLocalVector(dm, &localX);
483: MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));
484: *diff = PetscSqrtReal(*diff);
485: return(0);
486: }
490: /*@
491: DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
493: Input Parameters:
494: + dm - The mesh
495: . X - Local input vector
496: - user - The user context
498: Output Parameter:
499: . F - Local output vector
501: Note:
502: The second member of the user context must be an FEMContext.
504: We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
505: like a GPU, or vectorize on a multicore machine.
507: Level: developer
509: .seealso: DMPlexComputeJacobianActionFEM()
510: @*/
511: PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
512: {
513: DM_Plex *mesh = (DM_Plex *) dm->data;
514: PetscFEM *fem = (PetscFEM *) user;
515: PetscFE *fe = fem->fe;
516: PetscFE *feAux = fem->feAux;
517: PetscFE *feBd = fem->feBd;
518: const char *name = "Residual";
519: DM dmAux;
520: Vec A;
521: PetscQuadrature q;
522: PetscCellGeometry geom;
523: PetscSection section, sectionAux;
524: PetscReal *v0, *J, *invJ, *detJ;
525: PetscScalar *elemVec, *u, *a = NULL;
526: PetscInt dim, Nf, NfAux = 0, f, numCells, cStart, cEnd, c;
527: PetscInt cellDof = 0, numComponents = 0;
528: PetscInt cellDofAux = 0, numComponentsAux = 0;
529: PetscErrorCode ierr;
532: PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
533: DMPlexGetDimension(dm, &dim);
534: DMGetDefaultSection(dm, §ion);
535: PetscSectionGetNumFields(section, &Nf);
536: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
537: numCells = cEnd - cStart;
538: for (f = 0; f < Nf; ++f) {
539: PetscInt Nb, Nc;
541: PetscFEGetDimension(fe[f], &Nb);
542: PetscFEGetNumComponents(fe[f], &Nc);
543: cellDof += Nb*Nc;
544: numComponents += Nc;
545: }
546: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
547: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
548: if (dmAux) {
549: DMGetDefaultSection(dmAux, §ionAux);
550: PetscSectionGetNumFields(sectionAux, &NfAux);
551: }
552: for (f = 0; f < NfAux; ++f) {
553: PetscInt Nb, Nc;
555: PetscFEGetDimension(feAux[f], &Nb);
556: PetscFEGetNumComponents(feAux[f], &Nc);
557: cellDofAux += Nb*Nc;
558: numComponentsAux += Nc;
559: }
560: DMPlexProjectFunctionLocal(dm, fe, fem->bcFuncs, fem->bcCtxs, INSERT_BC_VALUES, X);
561: VecSet(F, 0.0);
562: PetscMalloc6(numCells*cellDof,&u,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof,&elemVec);
563: if (dmAux) {PetscMalloc1(numCells*cellDofAux, &a);}
564: for (c = cStart; c < cEnd; ++c) {
565: PetscScalar *x = NULL;
566: PetscInt i;
568: DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
569: if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
570: DMPlexVecGetClosure(dm, section, X, c, NULL, &x);
571: for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
572: DMPlexVecRestoreClosure(dm, section, X, c, NULL, &x);
573: if (dmAux) {
574: DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);
575: for (i = 0; i < cellDofAux; ++i) a[c*cellDofAux+i] = x[i];
576: DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);
577: }
578: }
579: for (f = 0; f < Nf; ++f) {
580: void (*f0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->f0Funcs[f];
581: void (*f1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->f1Funcs[f];
582: PetscInt Nb;
583: /* Conforming batches */
584: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
585: /* Remainder */
586: PetscInt Nr, offset;
588: PetscFEGetQuadrature(fe[f], &q);
589: PetscFEGetDimension(fe[f], &Nb);
590: PetscFEGetTileSizes(fe[f], NULL, &numBlocks, NULL, &numBatches);
591: blockSize = Nb*q.numPoints;
592: batchSize = numBlocks * blockSize;
593: PetscFESetTileSizes(fe[f], blockSize, numBlocks, batchSize, numBatches);
594: numChunks = numCells / (numBatches*batchSize);
595: Ne = numChunks*numBatches*batchSize;
596: Nr = numCells % (numBatches*batchSize);
597: offset = numCells - Nr;
598: geom.v0 = v0;
599: geom.J = J;
600: geom.invJ = invJ;
601: geom.detJ = detJ;
602: PetscFEIntegrateResidual(fe[f], Ne, Nf, fe, f, geom, u, NfAux, feAux, a, f0, f1, elemVec);
603: geom.v0 = &v0[offset*dim];
604: geom.J = &J[offset*dim*dim];
605: geom.invJ = &invJ[offset*dim*dim];
606: geom.detJ = &detJ[offset];
607: PetscFEIntegrateResidual(fe[f], Nr, Nf, fe, f, geom, &u[offset*cellDof], NfAux, feAux, &a[offset*cellDofAux], f0, f1, &elemVec[offset*cellDof]);
608: }
609: for (c = cStart; c < cEnd; ++c) {
610: if (mesh->printFEM > 1) {DMPrintCellVector(c, name, cellDof, &elemVec[c*cellDof]);}
611: DMPlexVecSetClosure(dm, section, F, c, &elemVec[c*cellDof], ADD_VALUES);
612: }
613: PetscFree6(u,v0,J,invJ,detJ,elemVec);
614: if (dmAux) {PetscFree(a);}
615: if (feBd) {
616: DMLabel label, depth;
617: IS pointIS;
618: const PetscInt *points;
619: PetscInt dep, numPoints, p, numFaces;
620: PetscReal *n;
622: DMPlexGetLabel(dm, "boundary", &label);
623: DMPlexGetDepthLabel(dm, &depth);
624: DMLabelGetStratumSize(label, 1, &numPoints);
625: DMLabelGetStratumIS(label, 1, &pointIS);
626: ISGetIndices(pointIS, &points);
627: for (f = 0, cellDof = 0, numComponents = 0; f < Nf; ++f) {
628: PetscInt Nb, Nc;
630: PetscFEGetDimension(feBd[f], &Nb);
631: PetscFEGetNumComponents(feBd[f], &Nc);
632: cellDof += Nb*Nc;
633: numComponents += Nc;
634: }
635: for (p = 0, numFaces = 0; p < numPoints; ++p) {
636: DMLabelGetValue(depth, points[p], &dep);
637: if (dep == dim-1) ++numFaces;
638: }
639: PetscMalloc7(numFaces*cellDof,&u,numFaces*dim,&v0,numFaces*dim,&n,numFaces*dim*dim,&J,numFaces*dim*dim,&invJ,numFaces,&detJ,numFaces*cellDof,&elemVec);
640: for (p = 0, f = 0; p < numPoints; ++p) {
641: const PetscInt point = points[p];
642: PetscScalar *x = NULL;
643: PetscInt i;
645: DMLabelGetValue(depth, points[p], &dep);
646: if (dep != dim-1) continue;
647: DMPlexComputeCellGeometry(dm, point, &v0[f*dim], &J[f*dim*dim], &invJ[f*dim*dim], &detJ[f]);
648: DMPlexComputeCellGeometryFVM(dm, point, NULL, NULL, &n[f*dim]);
649: if (detJ[f] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for face %d", detJ[f], point);
650: DMPlexVecGetClosure(dm, section, X, point, NULL, &x);
651: for (i = 0; i < cellDof; ++i) u[f*cellDof+i] = x[i];
652: DMPlexVecRestoreClosure(dm, section, X, point, NULL, &x);
653: ++f;
654: }
655: for (f = 0; f < Nf; ++f) {
656: void (*f0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[]) = fem->f0BdFuncs[f];
657: void (*f1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[]) = fem->f1BdFuncs[f];
658: PetscInt Nb;
659: /* Conforming batches */
660: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
661: /* Remainder */
662: PetscInt Nr, offset;
664: PetscFEGetQuadrature(feBd[f], &q);
665: PetscFEGetDimension(feBd[f], &Nb);
666: PetscFEGetTileSizes(feBd[f], NULL, &numBlocks, NULL, &numBatches);
667: blockSize = Nb*q.numPoints;
668: batchSize = numBlocks * blockSize;
669: PetscFESetTileSizes(feBd[f], blockSize, numBlocks, batchSize, numBatches);
670: numChunks = numFaces / (numBatches*batchSize);
671: Ne = numChunks*numBatches*batchSize;
672: Nr = numFaces % (numBatches*batchSize);
673: offset = numFaces - Nr;
674: geom.v0 = v0;
675: geom.n = n;
676: geom.J = J;
677: geom.invJ = invJ;
678: geom.detJ = detJ;
679: PetscFEIntegrateBdResidual(feBd[f], Ne, Nf, feBd, f, geom, u, 0, NULL, NULL, f0, f1, elemVec);
680: geom.v0 = &v0[offset*dim];
681: geom.n = &n[offset*dim];
682: geom.J = &J[offset*dim*dim];
683: geom.invJ = &invJ[offset*dim*dim];
684: geom.detJ = &detJ[offset];
685: PetscFEIntegrateBdResidual(feBd[f], Nr, Nf, feBd, f, geom, &u[offset*cellDof], 0, NULL, NULL, f0, f1, &elemVec[offset*cellDof]);
686: }
687: for (p = 0, f = 0; p < numPoints; ++p) {
688: const PetscInt point = points[p];
690: DMLabelGetValue(depth, point, &dep);
691: if (dep != dim-1) continue;
692: if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", cellDof, &elemVec[f*cellDof]);}
693: DMPlexVecSetClosure(dm, NULL, F, point, &elemVec[f*cellDof], ADD_VALUES);
694: ++f;
695: }
696: ISRestoreIndices(pointIS, &points);
697: ISDestroy(&pointIS);
698: PetscFree7(u,v0,n,J,invJ,detJ,elemVec);
699: }
700: if (mesh->printFEM) {DMPrintLocalVec(dm, name, mesh->printTol, F);}
701: PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
702: return(0);
703: }
707: /*@C
708: DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
710: Input Parameters:
711: + dm - The mesh
712: . J - The Jacobian shell matrix
713: . X - Local input vector
714: - user - The user context
716: Output Parameter:
717: . F - Local output vector
719: Note:
720: The second member of the user context must be an FEMContext.
722: We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
723: like a GPU, or vectorize on a multicore machine.
725: Level: developer
727: .seealso: DMPlexComputeResidualFEM()
728: @*/
729: PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
730: {
731: DM_Plex *mesh = (DM_Plex *) dm->data;
732: PetscFEM *fem = (PetscFEM *) user;
733: PetscFE *fe = fem->fe;
734: PetscQuadrature quad;
735: PetscCellGeometry geom;
736: PetscSection section;
737: JacActionCtx *jctx;
738: PetscReal *v0, *J, *invJ, *detJ;
739: PetscScalar *elemVec, *u, *a;
740: PetscInt dim, numFields, field, numCells, cStart, cEnd, c;
741: PetscInt cellDof = 0;
742: PetscErrorCode ierr;
745: /* PetscLogEventBegin(DMPLEX_JacobianActionFEM,dm,0,0,0); */
746: MatShellGetContext(Jac, &jctx);
747: DMPlexGetDimension(dm, &dim);
748: DMGetDefaultSection(dm, §ion);
749: PetscSectionGetNumFields(section, &numFields);
750: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
751: numCells = cEnd - cStart;
752: for (field = 0; field < numFields; ++field) {
753: PetscInt Nb, Nc;
755: PetscFEGetDimension(fe[field], &Nb);
756: PetscFEGetNumComponents(fe[field], &Nc);
757: cellDof += Nb*Nc;
758: }
759: VecSet(F, 0.0);
760: PetscMalloc7(numCells*cellDof,&u,numCells*cellDof,&a,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof,&elemVec);
761: for (c = cStart; c < cEnd; ++c) {
762: PetscScalar *x = NULL;
763: PetscInt i;
765: DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
766: if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
767: DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);
768: for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
769: DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);
770: DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);
771: for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
772: DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);
773: }
774: for (field = 0; field < numFields; ++field) {
775: PetscInt Nb;
776: /* Conforming batches */
777: PetscInt numBlocks = 1;
778: PetscInt numBatches = 1;
779: PetscInt numChunks, Ne, blockSize, batchSize;
780: /* Remainder */
781: PetscInt Nr, offset;
783: PetscFEGetQuadrature(fe[field], &quad);
784: PetscFEGetDimension(fe[field], &Nb);
785: blockSize = Nb*quad.numPoints;
786: batchSize = numBlocks * blockSize;
787: numChunks = numCells / (numBatches*batchSize);
788: Ne = numChunks*numBatches*batchSize;
789: Nr = numCells % (numBatches*batchSize);
790: offset = numCells - Nr;
791: geom.v0 = v0;
792: geom.J = J;
793: geom.invJ = invJ;
794: geom.detJ = detJ;
795: PetscFEIntegrateJacobianAction(fe[field], Ne, numFields, fe, field, geom, u, a, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);
796: geom.v0 = &v0[offset*dim];
797: geom.J = &J[offset*dim*dim];
798: geom.invJ = &invJ[offset*dim*dim];
799: geom.detJ = &detJ[offset];
800: PetscFEIntegrateJacobianAction(fe[field], Nr, numFields, fe, field, geom, &u[offset*cellDof], &a[offset*cellDof],
801: fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);
802: }
803: for (c = cStart; c < cEnd; ++c) {
804: if (mesh->printFEM > 1) {DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);}
805: DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);
806: }
807: PetscFree7(u,a,v0,J,invJ,detJ,elemVec);
808: if (mesh->printFEM) {
809: PetscMPIInt rank, numProcs;
810: PetscInt p;
812: MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
813: MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);
814: PetscPrintf(PetscObjectComm((PetscObject)dm), "Jacobian Action:\n");
815: for (p = 0; p < numProcs; ++p) {
816: if (p == rank) {VecView(F, PETSC_VIEWER_STDOUT_SELF);}
817: PetscBarrier((PetscObject) dm);
818: }
819: }
820: /* PetscLogEventEnd(DMPLEX_JacobianActionFEM,dm,0,0,0); */
821: return(0);
822: }
826: /*@
827: DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
829: Input Parameters:
830: + dm - The mesh
831: . X - Local input vector
832: - user - The user context
834: Output Parameter:
835: . Jac - Jacobian matrix
837: Note:
838: The second member of the user context must be an FEMContext.
840: We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
841: like a GPU, or vectorize on a multicore machine.
843: Level: developer
845: .seealso: FormFunctionLocal()
846: @*/
847: PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
848: {
849: DM_Plex *mesh = (DM_Plex *) dm->data;
850: PetscFEM *fem = (PetscFEM *) user;
851: PetscFE *fe = fem->fe;
852: PetscFE *feAux = fem->feAux;
853: const char *name = "Jacobian";
854: DM dmAux;
855: Vec A;
856: PetscQuadrature quad;
857: PetscCellGeometry geom;
858: PetscSection section, globalSection, sectionAux;
859: PetscReal *v0, *J, *invJ, *detJ;
860: PetscScalar *elemMat, *u, *a;
861: PetscInt dim, Nf, NfAux = 0, f, fieldI, fieldJ, numCells, cStart, cEnd, c;
862: PetscInt cellDof = 0, numComponents = 0;
863: PetscInt cellDofAux = 0, numComponentsAux = 0;
864: PetscBool isShell;
865: PetscErrorCode ierr;
868: PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
869: DMPlexGetDimension(dm, &dim);
870: DMGetDefaultSection(dm, §ion);
871: DMGetDefaultGlobalSection(dm, &globalSection);
872: PetscSectionGetNumFields(section, &Nf);
873: DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
874: numCells = cEnd - cStart;
875: for (f = 0; f < Nf; ++f) {
876: PetscInt Nb, Nc;
878: PetscFEGetDimension(fe[f], &Nb);
879: PetscFEGetNumComponents(fe[f], &Nc);
880: cellDof += Nb*Nc;
881: numComponents += Nc;
882: }
883: PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
884: PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
885: if (dmAux) {
886: DMGetDefaultSection(dmAux, §ionAux);
887: PetscSectionGetNumFields(sectionAux, &NfAux);
888: }
889: for (f = 0; f < NfAux; ++f) {
890: PetscInt Nb, Nc;
892: PetscFEGetDimension(feAux[f], &Nb);
893: PetscFEGetNumComponents(feAux[f], &Nc);
894: cellDofAux += Nb*Nc;
895: numComponentsAux += Nc;
896: }
897: DMPlexProjectFunctionLocal(dm, fe, fem->bcFuncs, fem->bcCtxs, INSERT_BC_VALUES, X);
898: MatZeroEntries(JacP);
899: PetscMalloc6(numCells*cellDof,&u,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof*cellDof,&elemMat);
900: if (dmAux) {PetscMalloc1(numCells*cellDofAux, &a);}
901: for (c = cStart; c < cEnd; ++c) {
902: PetscScalar *x = NULL;
903: PetscInt i;
905: DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
906: if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
907: DMPlexVecGetClosure(dm, section, X, c, NULL, &x);
908: for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
909: DMPlexVecRestoreClosure(dm, section, X, c, NULL, &x);
910: if (dmAux) {
911: DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);
912: for (i = 0; i < cellDofAux; ++i) a[c*cellDofAux+i] = x[i];
913: DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);
914: }
915: }
916: PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));
917: for (fieldI = 0; fieldI < Nf; ++fieldI) {
918: PetscInt Nb;
919: /* Conforming batches */
920: PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
921: /* Remainder */
922: PetscInt Nr, offset;
924: PetscFEGetQuadrature(fe[fieldI], &quad);
925: PetscFEGetDimension(fe[fieldI], &Nb);
926: PetscFEGetTileSizes(fe[fieldI], NULL, &numBlocks, NULL, &numBatches);
927: blockSize = Nb*quad.numPoints;
928: batchSize = numBlocks * blockSize;
929: PetscFESetTileSizes(fe[fieldI], blockSize, numBlocks, batchSize, numBatches);
930: numChunks = numCells / (numBatches*batchSize);
931: Ne = numChunks*numBatches*batchSize;
932: Nr = numCells % (numBatches*batchSize);
933: offset = numCells - Nr;
934: for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
935: void (*g0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g0Funcs[fieldI*Nf+fieldJ];
936: void (*g1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g1Funcs[fieldI*Nf+fieldJ];
937: void (*g2)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g2Funcs[fieldI*Nf+fieldJ];
938: void (*g3)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g3Funcs[fieldI*Nf+fieldJ];
940: geom.v0 = v0;
941: geom.J = J;
942: geom.invJ = invJ;
943: geom.detJ = detJ;
944: PetscFEIntegrateJacobian(fe[fieldI], Ne, Nf, fe, fieldI, fieldJ, geom, u, NfAux, feAux, a, g0, g1, g2, g3, elemMat);
945: geom.v0 = &v0[offset*dim];
946: geom.J = &J[offset*dim*dim];
947: geom.invJ = &invJ[offset*dim*dim];
948: geom.detJ = &detJ[offset];
949: PetscFEIntegrateJacobian(fe[fieldI], Nr, Nf, fe, fieldI, fieldJ, geom, &u[offset*cellDof], NfAux, feAux, &a[offset*cellDofAux], g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);
950: }
951: }
952: for (c = cStart; c < cEnd; ++c) {
953: if (mesh->printFEM > 1) {DMPrintCellMatrix(c, name, cellDof, cellDof, &elemMat[c*cellDof*cellDof]);}
954: DMPlexMatSetClosure(dm, section, globalSection, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);
955: }
956: PetscFree6(u,v0,J,invJ,detJ,elemMat);
957: if (dmAux) {PetscFree(a);}
958: MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
959: MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
960: if (mesh->printFEM) {
961: PetscPrintf(PETSC_COMM_WORLD, "%s:\n", name);
962: MatChop(JacP, 1.0e-10);
963: MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);
964: }
965: PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
966: PetscObjectTypeCompare((PetscObject) Jac, MATSHELL, &isShell);
967: if (isShell) {
968: JacActionCtx *jctx;
970: MatShellGetContext(Jac, &jctx);
971: VecCopy(X, jctx->u);
972: }
973: *str = SAME_NONZERO_PATTERN;
974: return(0);
975: }