Actual source code: bdlinear.c
1: #ifdef PETSC_RCS_HEADER
2: static char vcid[] = "$Id: bdlinear.c,v 1.4 2000/01/10 03:54:15 knepley Exp $";
3: #endif
5: /*
6: Defines piecewise linear 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----2
22: */
24: static int BoundaryDiscDestroy_Triangular_2D_Linear(Discretization disc) {
26: return(0);
27: }
29: static int BoundaryDiscView_Triangular_2D_Linear_File(Discretization disc, PetscViewer viewer)
30: {
32: PetscViewerASCIIPrintf(viewer, "Linear boundary discretizationn");
33: PetscViewerASCIIPrintf(viewer, " %d shape functions per componentn", disc->funcs);
34: PetscViewerASCIIPrintf(viewer, " %d registered operatorsn", disc->numOps);
35: return(0);
36: }
38: static int BoundaryDiscView_Triangular_2D_Linear(Discretization disc, PetscViewer viewer) {
39: PetscTruth isascii;
40: int ierr;
43: PetscTypeCompare((PetscObject) viewer, PETSC_VIEWER_ASCII, &isascii);
44: if (isascii == PETSC_TRUE) {
45: BoundaryDiscView_Triangular_2D_Linear_File(disc, viewer);
46: }
47: return(0);
48: }
50: static int BoundaryDiscEvaluateFunctionGalerkin_Triangular_2D_Linear(Discretization disc, Mesh mesh, PointFunction f,
51: PetscScalar alpha, int edge, PetscScalar *array, void *ctx)
52: {
53: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
54: EdgeContext *bdCtx = (EdgeContext *) ctx;
55: void *uCtx = bdCtx->ctx;
56: double *nodes = tri->nodes;
57: int *edges = tri->edges;
58: int rank = -1;
59: int comp = disc->comp; /* The number of components in this field */
60: int funcs = disc->funcs; /* The number of shape functions per component */
61: PetscScalar *funcVal = disc->funcVal; /* Function value at a quadrature point */
62: int numQuadPoints = disc->numQuadPoints; /* Number of points used for Gaussian quadrature */
63: double *quadPoints = disc->quadPoints; /* Points in the standard element for Gaussian quadrature */
64: double *quadWeights = disc->quadWeights; /* Weights in the standard element for Gaussian quadrature */
65: double *quadShapeFuncs = disc->quadShapeFuncs; /* Shape function evaluated at quadrature points */
66: double jac; /* |J| for map to standard element */
67: double x, y; /* The integration point */
68: double x11, y11, x21, y21;
69: int i, j, k, p;
70: #ifdef PETSC_USE_BOPT_g
71: PetscTruth opt;
72: #endif
73: int ierr;
76: MPI_Comm_rank(disc->comm, &rank);
78: /* For dummy collective calls */
79: if (array == PETSC_NULL) {
80: for(p = 0; p < numQuadPoints; p++) {
81: (*f)(0, 0, PETSC_NULL, PETSC_NULL, PETSC_NULL, PETSC_NULL, ctx);
82: }
83: return(0);
84: }
86: #ifdef PETSC_USE_BOPT_g
87: if ((edge < 0) || (edge >= mesh->numEdges)) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Invalid edge");
88: #endif
89: /* Calculate the determinant of the inverse Jacobian of the map to the standard element
90: which must be a constant for linear elements */
91: x11 = nodes[edges[edge*2] *2];
92: y11 = nodes[edges[edge*2] *2+1];
93: if (mesh->isPeriodic == PETSC_TRUE) {
94: x21 = MeshPeriodicDiffX(mesh, nodes[edges[edge*2+1]*2] - x11);
95: y21 = MeshPeriodicDiffY(mesh, nodes[edges[edge*2+1]*2+1] - y11);
96: } else {
97: x21 = nodes[edges[edge*2+1]*2] - x11;
98: y21 = nodes[edges[edge*2+1]*2+1] - y11;
99: }
100: jac = sqrt(x21*x21 + y21*y21);
101: if (jac < 1.0e-14) {
102: PetscPrintf(PETSC_COMM_SELF, "[%d]edge: %d x21: %g y21: %gn", rank, edge, x21, y21);
103: SETERRQ(PETSC_ERR_DISC_SING_JAC, "Singular Jacobian");
104: }
105: #ifdef PETSC_USE_BOPT_g
106: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
107: if (opt == PETSC_TRUE) {
108: PetscPrintf(PETSC_COMM_SELF, "[%d]edge: %d x21: %g y21: %g jac: %gn", rank, edge, x21, y21, jac);
109: }
110: #endif
112: /* Calculate element vector entries by Gaussian quadrature */
113: for(p = 0; p < numQuadPoints; p++) {
114: x = MeshPeriodicX(mesh, x21*quadPoints[p] + x11);
115: y = MeshPeriodicY(mesh, y21*quadPoints[p] + y11);
116: (*f)(1, comp, &x, &y, PETSC_NULL, funcVal, uCtx);
117: #ifdef PETSC_USE_BOPT_g
118: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
119: if (opt == PETSC_TRUE) {
120: PetscPrintf(PETSC_COMM_SELF, "[%d]p:%d jac: %g", rank, p, jac);
121: for(j = 0; j < comp; j++)
122: PetscPrintf(PETSC_COMM_SELF, " func[%d]: %g", j, PetscRealPart(funcVal[j]));
123: PetscPrintf(PETSC_COMM_SELF, "n");
124: }
125: #endif
127: for(i = 0, k = 0; i < funcs; i++) {
128: for(j = 0; j < comp; j++, k++) {
129: array[k] += alpha*funcVal[j]*quadShapeFuncs[p*funcs+i]*jac*quadWeights[p];
130: #ifdef PETSC_USE_BOPT_g
131: PetscOptionsHasName(PETSC_NULL, "-trace_assembly", &opt);
132: if (opt == PETSC_TRUE) {
133: PetscPrintf(PETSC_COMM_SELF, "[%d] array[%d]: %gn", rank, k, PetscRealPart(array[k]));
134: }
135: #endif
136: }
137: }
138: }
139: PetscLogFlops(6 + (4 + 5*funcs*comp) * numQuadPoints);
140: return(0);
141: }
143: static int BoundaryDiscEvaluateOperatorGalerkin_Triangular_2D_Linear(Discretization disc, Mesh mesh, int elemSize,
144: int rowStart, int colStart, int op, PetscScalar alpha,
145: int edge, PetscScalar *field, PetscScalar *mat, void *ctx)
146: {
147: Mesh_Triangular *tri = (Mesh_Triangular *) mesh->data;
148: EdgeContext *bdCtx = (EdgeContext *) ctx;
149: void *uCtx = bdCtx->ctx;
150: double *nodes = tri->nodes;
151: int *edges = tri->edges;
152: Operator oper = disc->operators[op]; /* The operator to discretize */
153: Discretization test = oper->test; /* The space of test functions */
154: int rowSize = test->size; /* The number of shape functions per element */
155: int colSize = disc->size; /* The number of test functions per element */
156: PetscScalar *precompInt = oper->precompInt; /* Precomputed integrals of the operator on shape functions */
157: OperatorFunction opFunc = oper->opFunc; /* Integrals of operators which depend on J */
158: double x21, y21; /* Coordinates of the element, with point 1 at the origin */
159: double jac; /* |J| for map to standard element */
160: double coords[MAX_CORNERS*2]; /* Coordinates of the element */
161: int i, j;
162: int rank;
163: int ierr;
166: MPI_Comm_rank(disc->comm, &rank);
167: #ifdef PETSC_USE_BOPT_g
168: /* Check for valid operator */
169: if ((op < 0) || (op >= disc->numOps) || (!disc->operators[op])) SETERRQ(PETSC_ERR_ARG_WRONG, "Invalid operator");
170: #endif
172: if (precompInt != PETSC_NULL) {
173: /* Calculate the determinant of the inverse Jacobian of the map to the standard element
174: which must be a constant for linear elements */
175: if (mesh->isPeriodic == PETSC_TRUE) {
176: x21 = MeshPeriodicDiffX(mesh, nodes[edges[edge*2+1]*2] - nodes[edges[edge*2]*2]);
177: y21 = MeshPeriodicDiffY(mesh, nodes[edges[edge*2+1]*2+1] - nodes[edges[edge*2]*2+1]);
178: } else {
179: x21 = nodes[edges[edge*2+1]*2] - nodes[edges[edge*2]*2];
180: y21 = nodes[edges[edge*2+1]*2+1] - nodes[edges[edge*2]*2+1];
181: }
182: jac = sqrt(x21*x21 + y21*y21);
183: if (jac < 1.0e-14) {
184: PetscPrintf(PETSC_COMM_SELF, "[%d]x21: %g y21: %g jac: %gn", rank, x21, y21, jac);
185: SETERRQ(PETSC_ERR_DISC_SING_JAC, "Singular Jacobian");
186: }
188: /* Calculate element matrix entries which are all precomputed */
189: for(i = 0; i < rowSize; i++)
190: for(j = 0; j < colSize; j++)
191: mat[(i+rowStart)*elemSize + j+colStart] += alpha*precompInt[i*colSize + j]*jac;
192: PetscLogFlops(6 + 2*rowSize*colSize);
193: } else {
194: if (opFunc == PETSC_NULL) SETERRQ(PETSC_ERR_ARG_CORRUPT, "Invalid function");
195: if (mesh->isPeriodic == PETSC_TRUE) {
196: coords[0*2+0] = nodes[edges[edge*2+0]*2];
197: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
198: coords[1*2+0] = MeshPeriodicRelativeX(mesh, nodes[edges[edge*2+1]*2], coords[0*2+0]);
199: coords[1*2+1] = MeshPeriodicRelativeY(mesh, nodes[edges[edge*2+1]*2+1], coords[0*2+1]);
200: } else {
201: coords[0*2+0] = nodes[edges[edge*2+0]*2];
202: coords[0*2+1] = nodes[edges[edge*2+0]*2+1];
203: coords[1*2+0] = nodes[edges[edge*2+1]*2];
204: coords[1*2+1] = nodes[edges[edge*2+1]*2+1];
205: }
207: (*opFunc)(disc, test, rowSize, colSize, rowStart, colStart, elemSize, coords, alpha, field, mat, uCtx);
208:
209: }
210: return(0);
211: }
213: static int BoundaryDiscEvaluateALEOperatorGalerkin_Triangular_2D_Linear(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_Linear(Discretization disc, Mesh mesh,
222: NonlinearOperator f, PetscScalar alpha,
223: int elem, int numArgs, PetscScalar **field, PetscScalar *vec, void *ctx)
224: {
225: SETERRQ(PETSC_ERR_SUP, " ");
226: }
228: static int BoundaryDiscEvaluateNonlinearALEOperatorGalerkin_Triangular_2D_Linear(Discretization disc, Mesh mesh,
229: NonlinearOperator f, PetscScalar alpha, int elem, int numArgs,
230: PetscScalar **field, PetscScalar *ALEfield, PetscScalar *vec,
231: void *ctx)
232: {
233: SETERRQ(PETSC_ERR_SUP, " ");
234: }
236: int BoundaryLaplacian_Triangular_2D_Linear(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: double x21, y21; /* Coordinates of the element, with point 1 at the origin */
241: double jac; /* |J| for map to standard element */
242: PetscScalar w; /* 1/(2 jac) */
243: int comp; /* Number of components */
244: int i;
247: /* Calculate the determinant of the inverse Jacobian of the map to the standard element
248: which must be a constant for linear elements - 1/|x_{21} y_{31} - x_{31} y_{21}| */
249: x21 = coords[2] - coords[0];
250: y21 = coords[3] - coords[1];
251: jac = sqrt(x21*x21 + y21*y21);
252: #ifdef PETSC_USE_BOPT_g
253: if (jac < 1.0e-14) {
254: PetscPrintf(PETSC_COMM_SELF, "x21: %g y21: %g jac: %gn", x21, y21, jac);
255: SETERRQ(PETSC_ERR_DISC_SING_JAC, "Singular Jacobian");
256: }
257: #endif
259: comp = rowSize/2;
260: w = 1.0/(2.0*jac);
261: w *= alpha;
262: for(i = 0; i < comp; i++)
263: {
264: /* phi^1 phi^1 */
265: array[(0*comp+i+globalRowStart)*globalSize + 0*comp+i+globalColStart] = 0.0;
266: /* phi^1 phi^2 */
267: array[(0*comp+i+globalRowStart)*globalSize + 1*comp+i+globalColStart] = 0.0;
268: /* phi^2 phi^1 */
269: array[(1*comp+i+globalRowStart)*globalSize + 0*comp+i+globalColStart] =
270: array[(0*comp+i+globalRowStart)*globalSize + 1*comp+i+globalColStart];
271: /* phi^2 phi^2 */
272: array[(1*comp+i+globalRowStart)*globalSize + 1*comp+i+globalColStart] = 0.0;
273: }
274: PetscLogFlops(47);
276: return(0);
277: }
279: int BoundaryDiscInterpolateField_Triangular_2D_Linear(Discretization disc, Mesh oldMesh, int elem, double x, double y, double z,
280: PetscScalar *oldFieldVal, PetscScalar *newFieldVal, InterpolationType type)
281: {
282: SETERRQ(PETSC_ERR_SUP, " ");
283: }
285: int BoundaryDiscInterpolateElementVec_Triangular_2D_Linear(Discretization disc, ElementVec vec,
286: Discretization newDisc, ElementVec newVec)
287: {
288: SETERRQ(PETSC_ERR_SUP, " ");
289: }
292: /*
293: BoundaryDiscSetupQuadrature_Triangular_2D_Linear - Setup Gaussian quadrature with a 5 point integration rule
295: Input Parameter:
296: . disc - The Discretization
297: */
298: int BoundaryDiscSetupQuadrature_Triangular_2D_Linear(Discretization disc) {
299: int dim = disc->dim;
300: int funcs = disc->funcs;
301: int p;
305: disc->numQuadPoints = 5;
306: PetscMalloc(disc->numQuadPoints*dim * sizeof(double), &disc->quadPoints);
307: PetscMalloc(disc->numQuadPoints * sizeof(double), &disc->quadWeights);
308: PetscMalloc(disc->numQuadPoints*funcs * sizeof(double), &disc->quadShapeFuncs);
309: PetscMalloc(disc->numQuadPoints*funcs*dim * sizeof(double), &disc->quadShapeFuncDers);
310: PetscLogObjectMemory(disc, (disc->numQuadPoints*(funcs*(dim+1) + dim+1)) * sizeof(double));
311: disc->quadPoints[0] = 0.0469101;
312: disc->quadWeights[0] = 0.118463;
313: disc->quadPoints[1] = 0.230765;
314: disc->quadWeights[1] = 0.239314;
315: disc->quadPoints[2] = 0.500000;
316: disc->quadWeights[2] = 0.284444;
317: disc->quadPoints[3] = 0.769235;
318: disc->quadWeights[3] = 0.239314;
319: disc->quadPoints[4] = 0.953090;
320: disc->quadWeights[4] = 0.118463;
321: for(p = 0; p < disc->numQuadPoints; p++) {
322: /* phi^0: 1 - xi */
323: disc->quadShapeFuncs[p*funcs+0] = 1.0 - disc->quadPoints[p];
324: disc->quadShapeFuncDers[p*funcs+0] = -1.0;
325: /* phi^1: xi */
326: disc->quadShapeFuncs[p*funcs+1] = disc->quadPoints[p];
327: disc->quadShapeFuncDers[p*funcs+1] = 1.0;
328: }
329: return(0);
330: }
332: /*
333: BoundaryDiscSetupOperators_Triangular_2D_Linear - Setup the default operators
335: Input Parameter:
336: . disc - The Discretization
337: */
338: int BoundaryDiscSetupOperators_Triangular_2D_Linear(Discretization disc) {
339: int comp = disc->comp;
340: int size = disc->size;
341: PetscScalar *precompInt;
342: int newOp;
343: int c, i, j;
344: int ierr;
347: /* The Identity operator I -- the matrix is symmetric */
348: PetscMalloc(size*size * sizeof(PetscScalar), &precompInt);
349: PetscLogObjectMemory(disc, size*size * sizeof(PetscScalar));
350: PetscMemzero(precompInt, size*size * sizeof(PetscScalar));
351: for(c = 0; c < comp; c++) {
352: precompInt[(0*comp+c)*size + 0*comp+c] = 1.0/3.0;
353: precompInt[(0*comp+c)*size + 1*comp+c] = 1.0/6.0;
354: precompInt[(1*comp+c)*size + 1*comp+c] = 1.0/3.0;
355: }
356: for(i = 0; i < size; i++) {
357: for(j = 0; j < i; j++) {
358: precompInt[i*size + j] = precompInt[j*size + i];
359: }
360: }
361: DiscretizationRegisterPrecomputedOperator(disc, precompInt, &newOp);
362: if (newOp != IDENTITY) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", IDENTITY);
363: /* The Laplacian operator Delta -- the matrix is symmetric */
364: DiscretizationRegisterOperator(disc, BoundaryLaplacian_Triangular_2D_Linear, &newOp);
365: if (newOp != LAPLACIAN) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", LAPLACIAN);
366: /* The Gradient operator nabla -- the matrix is rectangular */
367: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
368: if (newOp != GRADIENT) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", GRADIENT);
369: /* The Divergence operator nablacdot -- the matrix is rectangular */
370: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
371: if (newOp != DIVERGENCE) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", DIVERGENCE);
372: /* The weighted Laplacian operator -- the matrix is symmetric */
373: DiscretizationRegisterOperator(disc, PETSC_NULL, &newOp);
374: if (newOp != WEIGHTED_LAP) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Default operator %d not setup correctly", WEIGHTED_LAP);
375: return(0);
376: }
378: static struct _DiscretizationOps DOps = {PETSC_NULL/* DiscretizationSetup */,
379: BoundaryDiscSetupOperators_Triangular_2D_Linear,
380: PETSC_NULL/* DiscretizationSetFromOptions */,
381: BoundaryDiscView_Triangular_2D_Linear,
382: BoundaryDiscDestroy_Triangular_2D_Linear,
383: BoundaryDiscEvaluateFunctionGalerkin_Triangular_2D_Linear,
384: BoundaryDiscEvaluateOperatorGalerkin_Triangular_2D_Linear,
385: BoundaryDiscEvaluateALEOperatorGalerkin_Triangular_2D_Linear,
386: BoundaryDiscEvaluateNonlinearOperatorGalerkin_Triangular_2D_Linear,
387: BoundaryDiscEvaluateNonlinearALEOperatorGalerkin_Triangular_2D_Linear,
388: BoundaryDiscInterpolateField_Triangular_2D_Linear,
389: BoundaryDiscInterpolateElementVec_Triangular_2D_Linear};
391: EXTERN_C_BEGIN
392: int BoundaryDiscCreate_Triangular_2D_Linear(Discretization disc) {
393: int arg;
397: if (disc->comp <= 0) {
398: SETERRQ(PETSC_ERR_ARG_WRONG, "Discretization must have at least 1 component. Call DiscretizationSetNumComponents() to set this.");
399: }
400: PetscMemcpy(disc->ops, &DOps, sizeof(struct _DiscretizationOps));
401: disc->dim = 2;
402: disc->funcs = 2;
403: disc->size = disc->funcs*disc->comp;
405: DiscretizationSetupDefaultOperators(disc);
406: BoundaryDiscSetupQuadrature_Triangular_2D_Linear(disc);
408: /* Storage */
409: PetscMalloc(disc->comp * sizeof(PetscScalar), &disc->funcVal);
410: PetscMalloc(2 * sizeof(PetscScalar *), &disc->fieldVal);
411: for(arg = 0; arg < 2; arg++) {
412: PetscMalloc(disc->comp*(disc->dim+1) * sizeof(PetscScalar), &disc->fieldVal[arg]);
413: }
414: return(0);
415: }
416: EXTERN_C_END