Actual source code: bdquadratic.c
1: #ifdef PETSC_RCS_HEADER
2: static char vcid[] = "$Id: bdquadratic.c,v 1.4 2000/01/31 17:56:20 knepley Exp $";
3: #endif
5: /*
6: Defines piecewise quadratic function space on a two dimensional
7: grid. Suitable for finite element type discretization of a PDE.
8: */
10: #include "src/grid/discretization/discimpl.h" /*I "discretization.h" I*/
11: #include "src/mesh/impls/triangular/triimpl.h"
13: /* For precomputed integrals, the table is structured as follows:
15: precompInt[op,i,j] = int_{SE} <op phi^i(xi), phi^j(xi)> |J^{-1}|
17: where we recall that |J| is a constant for linear affine maps,
18: and the map of any triangle to the standard element is linear.
19: The numbering of the nodes in the standard element is
21: 1--3--2
22: */
24: static int BoundaryDiscDestroy_Triangular_2D_Quadratic(Discretization disc) {
26: return(0);
27: }
29: static int BoundaryDiscView_Triangular_2D_Quadratic_File(Discretization disc, PetscViewer viewer) {
31: PetscViewerASCIIPrintf(viewer, "Quadratic boundary discretizationn");
32: PetscViewerASCIIPrintf(viewer, " %d shape functions per componentn", disc->funcs);
33: PetscViewerASCIIPrintf(viewer, " %d registered operatorsn", disc->numOps);
34: return(0);
35: }
37: static int BoundaryDiscView_Triangular_2D_Quadratic(Discretization disc, PetscViewer viewer) {
38: PetscTruth isascii;
39: int ierr;
42: PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &isascii);
43: if (isascii == PETSC_TRUE) {
44: BoundaryDiscView_Triangular_2D_Quadratic_File(disc, viewer);
45: }
46: return(0);
47: }
49: static int BoundaryDiscEvaluateFunctionGalerkin_Triangular_2D_Quadratic(Discretization disc, Mesh mesh, PointFunction f,
50: PetscScalar alpha, int edge, PetscScalar *array, void *ctx)
51: {
52: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
53: EdgeContext *bdCtx = (EdgeContext *) ctx;
54: void *uCtx = bdCtx->ctx;
55: double *nodes = tri->nodes;
56: int *edges = tri->edges;
57: int comp = disc->comp; /* The number of components in this field */
58: int funcs = disc->funcs; /* The number of shape functions per component */
59: PetscScalar *funcVal = disc->funcVal; /* Function value at a quadrature point */
60: int numQuadPoints = disc->numQuadPoints; /* Number of points used for Gaussian quadrature */
61: double *quadWeights = disc->quadWeights; /* Weights in the standard element for Gaussian quadrature */
62: double *quadShapeFuncs = disc->quadShapeFuncs; /* Shape function evaluated at quadrature points */
63: double *quadShapeFuncDers = disc->quadShapeFuncDers; /* Shape function derivatives at quadrature points */
64: double jac; /* |J| for map to standard element */
65: double x, y; /* The integration point */
66: double dxxi; /* PartDer{x}{xi} */
67: double dyxi; /* PartDer{y}{eta} */
68: double coords[3*2];
69: int rank;
70: int i, j, k, p, func;
71: #ifdef PETSC_USE_BOPT_g
72: PetscTruth opt;
73: #endif
74: int ierr;
77: MPI_Comm_rank(disc->comm, &rank);
79: /* For dummy collective calls */
80: if (array == PETSC_NULL) {
81: for(p = 0; p < numQuadPoints; p++) {
82: (*f)(0, 0, PETSC_NULL, PETSC_NULL, PETSC_NULL, PETSC_NULL, ctx);
83: }
84: return(0);
85: }
87: #ifdef PETSC_USE_BOPT_g
88: if ((edge < 0) || (edge >= mesh->numEdges)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Invalid edge");
89: #endif
90: /* Calculate the determinant of the inverse Jacobian of the map to the standard element */
91: if (mesh->isPeriodic == PETSC_TRUE) {
92: coords[0*2] = nodes[edges[edge*2+0]*2];
93: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
94: coords[1*2+0] = MeshPeriodicRelativeX(mesh, nodes[edges[edge*2+1]*2], coords[0*2+0]);
95: coords[1*2+1] = MeshPeriodicRelativeY(mesh, nodes[edges[edge*2+1]*2+1], coords[0*2+1]);
96: coords[2*2+0] = MeshPeriodicRelativeX(mesh, nodes[bdCtx->midnode *2], coords[0*2+0]);
97: coords[2*2+1] = MeshPeriodicRelativeY(mesh, nodes[bdCtx->midnode *2+1], coords[0*2+1]);
98: } else {
99: coords[0*2] = nodes[edges[edge*2+0]*2];
100: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
101: coords[1*2] = nodes[edges[edge*2+1]*2];
102: coords[1*2+1] = nodes[edges[edge*2+1]*2+1];
103: coords[2*2] = nodes[bdCtx->midnode *2];
104: coords[2*2+1] = nodes[bdCtx->midnode *2+1];
105: }
106: #ifdef PETSC_USE_BOPT_g
107: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
108: if (opt == PETSC_TRUE) {
109: PetscPrintf(PETSC_COMM_SELF, "[%d]edge: %d x1: %g y1: %g x2: %g y2: %g x3: %g y3: %gn",
110: rank, edge, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
111: }
112: #endif
114: /* Calculate element vector entries by Gaussian quadrature */
115: for(p = 0; p < numQuadPoints; p++)
116: {
117: /* x = sum^{funcs}_{f=1} x_f phi^f(p)
118: PartDer{x}{xi}(p) = sum^{funcs}_{f=1} x_f PartDer{phi^f(p)}{xi}
119: y = sum^{funcs}_{f=1} y_f phi^f(p)
120: PartDer{y}{xi}(p) = sum^{funcs}_{f=1} y_f PartDer{phi^f(p)}{xi} */
121: x = 0.0; y = 0.0;
122: dxxi = 0.0; dyxi = 0.0;
123: for(func = 0; func < funcs; func++)
124: {
125: x += coords[func*2] *quadShapeFuncs[p*funcs+func];
126: dxxi += coords[func*2] *quadShapeFuncDers[p*funcs+func];
127: y += coords[func*2+1]*quadShapeFuncs[p*funcs+func];
128: dyxi += coords[func*2+1]*quadShapeFuncDers[p*funcs+func];
129: }
130: if (mesh->isPeriodic == PETSC_TRUE) {
131: x = MeshPeriodicX(mesh, x);
132: y = MeshPeriodicY(mesh, y);
133: }
134: jac = sqrt(dxxi*dxxi + dyxi*dyxi);
135: if (jac < 1.0e-14) {
136: PetscPrintf(PETSC_COMM_SELF, "[%d]p: %d x1: %g y1: %g x2: %g y2: %g x3: %g y3: %gn",
137: rank, p, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
138: SETERRQ(PETSC_ERR_DISC_SING_JAC, "Singular Jacobian");
139: }
140: (*f)(1, comp, &x, &y, PETSC_NULL, funcVal, uCtx);
141: #ifdef PETSC_USE_BOPT_g
142: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
143: if (opt == PETSC_TRUE) {
144: PetscPrintf(PETSC_COMM_SELF, "[%d]p:%d jac: %g", rank, p, jac);
145: for(j = 0; j < comp; j++)
146: PetscPrintf(PETSC_COMM_SELF, " func[%d]: %g", j, PetscRealPart(funcVal[j]));
147: PetscPrintf(PETSC_COMM_SELF, "n");
148: }
149: #endif
151: for(i = 0, k = 0; i < funcs; i++) {
152: for(j = 0; j < comp; j++, k++) {
153: array[k] += alpha*funcVal[j]*quadShapeFuncs[p*funcs+i]*jac*quadWeights[p];
154: #ifdef PETSC_USE_BOPT_g
155: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
156: if (opt == PETSC_TRUE) {
157: PetscPrintf(PETSC_COMM_SELF, "[%d] array[%d]: %gn", rank, k, PetscRealPart(array[k]));
158: }
159: #endif
160: }
161: }
162: }
163: PetscLogFlops((4 + 8*funcs + 5*funcs*comp) * numQuadPoints);
164: return(0);
165: }
167: static int BoundaryDiscEvaluateOperatorGalerkin_Triangular_2D_Quadratic(Discretization disc, Mesh mesh, int elemSize,
168: int rowStart, int colStart, int op, PetscScalar alpha,
169: int edge, PetscScalar *field, PetscScalar *mat, void *ctx)
170: {
171: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
172: EdgeContext *bdCtx = (EdgeContext *) ctx;
173: void *uCtx = bdCtx->ctx;
174: double *nodes = tri->nodes;
175: int *edges = tri->edges;
176: Operator oper = disc->operators[op]; /* The operator to discretize */
177: Discretization test = oper->test; /* The space of test functions */
178: int rowSize = test->size; /* The number of shape functions per element */
179: int colSize = disc->size; /* The number of test functions per element */
180: OperatorFunction opFunc = oper->opFunc; /* Integrals of operators which depend on J */
181: double coords[MAX_CORNERS*2]; /* Coordinates of the element */
182: int ierr;
185: #ifdef PETSC_USE_BOPT_g
186: /* Check for valid operator */
187: if ((op < 0) || (op >= disc->numOps) || (!disc->operators[op])) SETERRQ(PETSC_ERR_ARG_WRONG, "Invalid operator");
188: #endif
190: if (opFunc == PETSC_NULL) SETERRQ(PETSC_ERR_ARG_CORRUPT, "Invalid function");
191: if (mesh->isPeriodic == PETSC_TRUE) {
192: coords[0*2] = nodes[edges[edge*2+0]*2];
193: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
194: coords[1*2+0] = MeshPeriodicRelativeX(mesh, nodes[edges[edge*2+1]*2], coords[0*2+0]);
195: coords[1*2+1] = MeshPeriodicRelativeY(mesh, nodes[edges[edge*2+1]*2+1], coords[0*2+1]);
196: coords[2*2+0] = MeshPeriodicRelativeX(mesh, nodes[bdCtx->midnode *2], coords[0*2+0]);
197: coords[2*2+1] = MeshPeriodicRelativeY(mesh, nodes[bdCtx->midnode *2+1], coords[0*2+1]);
198: } else {
199: coords[0*2] = nodes[edges[edge*2+0]*2];
200: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
201: coords[1*2] = nodes[edges[edge*2+1]*2];
202: coords[1*2+1] = nodes[edges[edge*2+1]*2+1];
203: coords[2*2] = nodes[bdCtx->midnode *2];
204: coords[2*2+1] = nodes[bdCtx->midnode *2+1];
205: }
207: (*opFunc)(disc, test, rowSize, colSize, rowStart, colStart, elemSize, coords, alpha, field, mat, uCtx);
208:
210: return(0);
211: }
213: static int BoundaryDiscEvaluateALEOperatorGalerkin_Triangular_2D_Quadratic(Discretization disc, Mesh mesh, int elemSize,
214: int rowStart, int colStart, int op, PetscScalar alpha,
215: int elem, PetscScalar *field, PetscScalar *ALEfield, PetscScalar *mat,
216: void *ctx)
217: {
218: SETERRQ(PETSC_ERR_SUP, " ");
219: }
221: static int BoundaryDiscEvaluateNonlinearOperatorGalerkin_Triangular_2D_Quadratic(Discretization disc, Mesh mesh,
222: NonlinearOperator f, PetscScalar alpha, int elem,
223: int numArgs, PetscScalar **field, PetscScalar *vec, void *ctx)
224: {
225: SETERRQ(PETSC_ERR_SUP, " ");
226: }
228: static int BoundaryDiscEvaluateNonlinearALEOperatorGalerkin_Triangular_2D_Quadratic(Discretization disc, Mesh mesh,
229: NonlinearOperator f, PetscScalar alpha, int elem,
230: int numArgs, PetscScalar **field, PetscScalar *ALEfield,
231: PetscScalar *vec, void *ctx)
232: {
233: SETERRQ(PETSC_ERR_SUP, " ");
234: }
236: int BoundaryIdentity_Triangular_2D_Quadratic(Discretization disc, Discretization test, int rowSize, int colSize,
237: int globalRowStart, int globalColStart, int globalSize, double *coords,
238: PetscScalar alpha, PetscScalar *field, PetscScalar *array, void *ctx)
239: {
240: int numQuadPoints = disc->numQuadPoints; /* Number of points used for Gaussian quadrature */
241: double *quadWeights = disc->quadWeights; /* Weights in the standard element for Gaussian quadrature */
242: double *quadShapeFuncs = disc->quadShapeFuncs; /* Shape functions evaluated at quadrature points */
243: double *quadTestFuncs = test->quadShapeFuncs; /* Test functions evaluated at quadrature points */
244: double *quadShapeFuncDers = disc->quadShapeFuncDers; /* Shape function derivatives evaluated at quadrature points */
245: int comp = disc->comp; /* The number of field components */
246: int tcomp = test->comp; /* The number of field components */
247: int funcs = disc->funcs; /* The number of shape functions */
248: int tfuncs = test->funcs; /* The number of test functions */
249: double dxxi; /* PartDer{x}{xi} */
250: double dyxi; /* PartDer{y}{xi} */
251: double jac; /* |J| for map to standard element */
252: int i, j, c, f, p;
255: #ifdef PETSC_USE_BOPT_g
256: if (comp != tcomp) SETERRQ(PETSC_ERR_ARG_INCOMP, "Shape and test fields must have the same number of components");
257: #endif
258: /* Calculate element matrix entries by Gaussian quadrature */
259: for(p = 0; p < numQuadPoints; p++) {
260: /* PartDer{x}{xi}(p) = sum^{funcs}_{f=1} x_f PartDer{phi^f(p)}{xi}
261: PartDer{y}{xi}(p) = sum^{funcs}_{f=1} y_f PartDer{phi^f(p)}{xi} */
262: dxxi = 0.0; dyxi = 0.0;
263: for(f = 0; f < funcs; f++) {
264: dxxi += coords[f*2] *quadShapeFuncDers[p*funcs+f];
265: dyxi += coords[f*2+1]*quadShapeFuncDers[p*funcs+f];
266: }
267: jac = sqrt(dxxi*dxxi + dyxi*dyxi);
268: #ifdef PETSC_USE_BOPT_g
269: if (jac < 1.0e-14) {
270: PetscPrintf(PETSC_COMM_SELF, "p: %d x1: %g y1: %g x2: %g y2: %g x3: %g y3: %gn",
271: p, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
272: SETERRQ(PETSC_ERR_DISC_SING_JAC, "Singular Jacobian");
273: }
274: #endif
276: for(i = 0; i < tfuncs; i++) {
277: for(j = 0; j < funcs; j++) {
278: for(c = 0; c < comp; c++) {
279: array[(i*tcomp+c+globalRowStart)*globalSize + j*comp+c+globalColStart] +=
280: alpha*quadTestFuncs[p*tfuncs+i]*quadShapeFuncs[p*funcs+j]*jac*quadWeights[p];
281: }
282: }
283: }
284: }
285: PetscLogFlops((4*funcs + 4 + 5*funcs*funcs*comp) * numQuadPoints);
287: return(0);
288: }
290: int BoundaryDiscInterpolateField_Triangular_2D_Quadratic(Discretization disc, Mesh oldMesh, int elem, double x, double y, double z,
291: PetscScalar *oldFieldVal, PetscScalar *newFieldVal, InterpolationType type)
292: {
293: SETERRQ(PETSC_ERR_SUP, " ");
294: }
296: int BoundaryDiscInterpolateElementVec_Triangular_2D_Quadratic(Discretization disc, ElementVec vec,
297: Discretization newDisc, ElementVec newVec)
298: {
299: SETERRQ(PETSC_ERR_SUP, " ");
300: }
302: /*
303: BoundaryDiscSetupQuadrature_Triangular_2D_Linear - Setup Gaussian quadrature with a 5 point integration rule
305: Input Parameter:
306: . disc - The Discretization
307: */
308: int BoundaryDiscSetupQuadrature_Triangular_2D_Quadratic(Discretization disc) {
309: int dim = disc->dim;
310: int funcs = disc->funcs;
311: int p;
315: disc->numQuadPoints = 5;
316: PetscMalloc(disc->numQuadPoints*dim * sizeof(double), &disc->quadPoints);
317: PetscMalloc(disc->numQuadPoints * sizeof(double), &disc->quadWeights);
318: PetscMalloc(disc->numQuadPoints*funcs * sizeof(double), &disc->quadShapeFuncs);
319: PetscMalloc(disc->numQuadPoints*funcs*dim * sizeof(double), &disc->quadShapeFuncDers);
320: PetscLogObjectMemory(disc, (disc->numQuadPoints*(funcs*(dim+1) + dim+1)) * sizeof(double));
321: disc->quadPoints[0] = 0.0469101;
322: disc->quadWeights[0] = 0.118463;
323: disc->quadPoints[1] = 0.230765;
324: disc->quadWeights[1] = 0.239314;
325: disc->quadPoints[2] = 0.500000;
326: disc->quadWeights[2] = 0.284444;
327: disc->quadPoints[3] = 0.769235;
328: disc->quadWeights[3] = 0.239314;
329: disc->quadPoints[4] = 0.953090;
330: disc->quadWeights[4] = 0.118463;
331: for(p = 0; p < disc->numQuadPoints; p++) {
332: /* phi^0: (1 - xi) (1 - 2 xi) */
333: disc->quadShapeFuncs[p*funcs+0] = (1.0 - disc->quadPoints[p])*(1.0 - 2.0*disc->quadPoints[p]);
334: disc->quadShapeFuncDers[p*funcs+0] = 4.0*disc->quadPoints[p] - 3.0;
335: /* phi^1: -xi (1 - 2 xi) */
336: disc->quadShapeFuncs[p*funcs+1] = -disc->quadPoints[p]*(1.0 - 2.0*disc->quadPoints[p]);
337: disc->quadShapeFuncDers[p*funcs+1] = 4.0*disc->quadPoints[p] - 1.0;
338: /* phi^2: 4 xi (1 - xi) */
339: disc->quadShapeFuncs[p*funcs+2] = 4.0*disc->quadPoints[p]*(1.0 - disc->quadPoints[p]);
340: disc->quadShapeFuncDers[p*funcs+2] = 4.0 - 8.0*disc->quadPoints[p];
341: }
342: return(0);
343: }
345: /*
346: BoundaryDiscSetupOperators_Triangular_2D_Quadratic - Setup the default operators
348: Input Parameter:
349: . disc - The Discretization
350: */
351: int BoundaryDiscSetupOperators_Triangular_2D_Quadratic(Discretization disc) {
352: int newOp;
356: /* The Identity operator I -- the matrix is symmetric */
357: DiscretizationRegisterOperator(disc, BoundaryIdentity_Triangular_2D_Quadratic, &newOp);
358: if (newOp != IDENTITY) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", IDENTITY);
359: /* The Laplacian operator Delta -- the matrix is symmetric */
360: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
361: if (newOp != LAPLACIAN) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", LAPLACIAN);
362: /* The Gradient operator nabla -- the matrix is rectangular */
363: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
364: if (newOp != GRADIENT) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", GRADIENT);
365: /* The Divergence operator nablacdot -- the matrix is rectangular */
366: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
367: if (newOp != DIVERGENCE) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", DIVERGENCE);
368: /* The weighted Laplacian operator -- the matrix is symmetric */
369: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
370: if (newOp != WEIGHTED_LAP) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", WEIGHTED_LAP);
371: return(0);
372: }
374: static struct _DiscretizationOps DOps = {PETSC_NULL/* DiscretizationSetup */,
375: BoundaryDiscSetupOperators_Triangular_2D_Quadratic,
376: PETSC_NULL/* DiscretizationSetFromOptions */,
377: BoundaryDiscView_Triangular_2D_Quadratic,
378: BoundaryDiscDestroy_Triangular_2D_Quadratic,
379: BoundaryDiscEvaluateFunctionGalerkin_Triangular_2D_Quadratic,
380: BoundaryDiscEvaluateOperatorGalerkin_Triangular_2D_Quadratic,
381: BoundaryDiscEvaluateALEOperatorGalerkin_Triangular_2D_Quadratic,
382: BoundaryDiscEvaluateNonlinearOperatorGalerkin_Triangular_2D_Quadratic,
383: BoundaryDiscEvaluateNonlinearALEOperatorGalerkin_Triangular_2D_Quadratic,
384: BoundaryDiscInterpolateField_Triangular_2D_Quadratic,
385: BoundaryDiscInterpolateElementVec_Triangular_2D_Quadratic};
387: EXTERN_C_BEGIN
388: int BoundaryDiscCreate_Triangular_2D_Quadratic(Discretization disc) {
389: int sarg;
393: if (disc->comp <= 0) {
394: SETERRQ(PETSC_ERR_ARG_WRONG, "Discretization must have at least 1 component. Call DiscretizationSetNumComponents() to set this.");
395: }
396: PetscMemcpy(disc->ops, &DOps, sizeof(struct _DiscretizationOps));
397: disc->dim = 2;
398: disc->funcs = 3;
399: disc->size = disc->funcs*disc->comp;
401: DiscretizationSetupDefaultOperators(disc);
402: BoundaryDiscSetupQuadrature_Triangular_2D_Quadratic(disc);
404: /* Storage */
405: PetscMalloc(disc->comp * sizeof(PetscScalar), &disc->funcVal);
406: PetscMalloc(2 * sizeof(PetscScalar *), &disc->fieldVal);
407: for(sarg = 0; sarg < 2; sarg++) {
408: PetscMalloc(disc->comp*(disc->dim+1) * sizeof(PetscScalar), &disc->fieldVal[sarg]);
409: }
410: return(0);
411: }
412: EXTERN_C_END