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