Actual source code: ex1.c

  1: /*$Id: ex1.c,v 1.46 2001/04/10 19:37:11 bsmith Exp $*/
  2: /*
  3:        Formatted test for TS routines.

  5:           Solves U_t = U_xx 
  6:      F(t,u) = (u_i+1 - 2u_i + u_i-1)/h^2
  7:        using several different schemes. 
  8: */

 10: static char help[] = "Solves 1D heat equation.nn";

 12: #include "petscda.h"
 13: #include "petscsys.h"
 14: #include "petscts.h"

 16: #define PETSC_NEAR(a,b,c) (!(PetscAbsDouble((a)-(b)) > (c)*PetscMax(PetscAbsDouble(a),PetscAbsDouble(b))))

 18: typedef struct {
 19:   Vec    global,local,localwork,solution;    /* location for local work (with ghost points) vector */
 20:   DA     da;                    /* manages ghost point communication */
 21:   PetscViewer viewer1,viewer2;
 22:   int    M;                     /* total number of grid points */
 23:   double h;                     /* mesh width h = 1/(M-1) */
 24:   double norm_2,norm_max;
 25:   int    nox;                   /* indicates problem is to be run without graphics */
 26: } AppCtx;

 28: extern int Monitor(TS,int,double,Vec,void *);
 29: extern int RHSFunctionHeat(TS,double,Vec,Vec,void*);
 30: extern int RHSMatrixFree(Mat,Vec,Vec);
 31: extern int Initial(Vec,void*);
 32: extern int RHSMatrixHeat(TS,double,Mat *,Mat *,MatStructure *,void *);
 33: extern int RHSJacobianHeat(TS,double,Vec,Mat*,Mat*,MatStructure *,void*);

 35: #define linear_no_matrix       0
 36: #define linear_no_time         1
 37: #define linear                 2
 38: #define nonlinear_no_jacobian  3
 39: #define nonlinear              4

 41: int main(int argc,char **argv)
 42: {
 43:   int           ierr,time_steps = 100,steps,size,m;
 44:   int           problem = linear_no_matrix;
 45:   PetscTruth    flg;
 46:   AppCtx        appctx;
 47:   double        dt,ftime;
 48:   TS            ts;
 49:   Mat           A = 0;
 50:   MatStructure  A_structure;
 51:   TSProblemType tsproblem = TS_LINEAR;
 52:   PetscDraw     draw;
 53:   PetscViewer   viewer;
 54:   char          tsinfo[120];
 55: 
 56:   PetscInitialize(&argc,&argv,(char*)0,help);
 57:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

 59:   appctx.M = 60;
 60:   PetscOptionsGetInt(PETSC_NULL,"-M",&appctx.M,PETSC_NULL);
 61:   PetscOptionsGetInt(PETSC_NULL,"-time",&time_steps,PETSC_NULL);
 62: 
 63:   PetscOptionsHasName(PETSC_NULL,"-nox",&flg);
 64:   if (flg) appctx.nox = 1; else appctx.nox = 0;
 65:   appctx.norm_2 = 0.0; appctx.norm_max = 0.0;

 67:   /* Set up the ghost point communication pattern */
 68:   DACreate1d(PETSC_COMM_WORLD,DA_NONPERIODIC,appctx.M,1,1,PETSC_NULL,&appctx.da);
 69:   DACreateGlobalVector(appctx.da,&appctx.global);
 70:   VecGetLocalSize(appctx.global,&m);
 71:   DACreateLocalVector(appctx.da,&appctx.local);

 73:   /* Set up display to show wave graph */

 75:   PetscViewerDrawOpen(PETSC_COMM_WORLD,0,"",80,380,400,160,&appctx.viewer1);
 76:   PetscViewerDrawGetDraw(appctx.viewer1,0,&draw);
 77:   PetscDrawSetDoubleBuffer(draw);
 78:   PetscViewerDrawOpen(PETSC_COMM_WORLD,0,"",80,0,400,160,&appctx.viewer2);
 79:   PetscViewerDrawGetDraw(appctx.viewer2,0,&draw);
 80:   PetscDrawSetDoubleBuffer(draw);


 83:   /* make work array for evaluating right hand side function */
 84:   VecDuplicate(appctx.local,&appctx.localwork);

 86:   /* make work array for storing exact solution */
 87:   VecDuplicate(appctx.global,&appctx.solution);

 89:   appctx.h = 1.0/(appctx.M-1.0);

 91:   /* set initial conditions */
 92:   Initial(appctx.global,&appctx);
 93: 
 94:   /*
 95:      This example is written to allow one to easily test parts 
 96:     of TS, we do not expect users to generally need to use more
 97:     then a single TSProblemType
 98:   */
 99:   PetscOptionsHasName(PETSC_NULL,"-linear_no_matrix",&flg);
100:   if (flg) {
101:     tsproblem = TS_LINEAR;
102:     problem   = linear_no_matrix;
103:   }
104:   PetscOptionsHasName(PETSC_NULL,"-linear_constant_matrix",&flg);
105:   if (flg) {
106:     tsproblem = TS_LINEAR;
107:     problem   = linear_no_time;
108:   }
109:   PetscOptionsHasName(PETSC_NULL,"-linear_variable_matrix",&flg);
110:   if (flg) {
111:     tsproblem = TS_LINEAR;
112:     problem   = linear;
113:   }
114:   PetscOptionsHasName(PETSC_NULL,"-nonlinear_no_jacobian",&flg);
115:   if (flg) {
116:     tsproblem = TS_NONLINEAR;
117:     problem   = nonlinear_no_jacobian;
118:   }
119:   PetscOptionsHasName(PETSC_NULL,"-nonlinear_jacobian",&flg);
120:   if (flg) {
121:     tsproblem = TS_NONLINEAR;
122:     problem   = nonlinear;
123:   }
124: 
125:   /* make timestep context */
126:   TSCreate(PETSC_COMM_WORLD,tsproblem,&ts);
127:   TSSetMonitor(ts,Monitor,&appctx,PETSC_NULL);

129:   dt = appctx.h*appctx.h/2.01;

131:   if (problem == linear_no_matrix) {
132:     /*
133:          The user provides the RHS as a Shell matrix.
134:     */
135:     MatCreateShell(PETSC_COMM_WORLD,m,appctx.M,appctx.M,appctx.M,&appctx,&A);
136:     MatShellSetOperation(A,MATOP_MULT,(void(*)())RHSMatrixFree);
137:     TSSetRHSMatrix(ts,A,A,PETSC_NULL,&appctx);
138:   } else if (problem == linear_no_time) {
139:     /*
140:          The user provides the RHS as a matrix
141:     */
142:     MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,appctx.M,appctx.M,&A);
143:     MatSetFromOptions(A);
144:     RHSMatrixHeat(ts,0.0,&A,&A,&A_structure,&appctx);
145:     TSSetRHSMatrix(ts,A,A,PETSC_NULL,&appctx);
146:   } else if (problem == linear) {
147:     /*
148:          The user provides the RHS as a time dependent matrix
149:     */
150:     MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,appctx.M,appctx.M,&A);
151:     MatSetFromOptions(A);
152:     RHSMatrixHeat(ts,0.0,&A,&A,&A_structure,&appctx);
153:     TSSetRHSMatrix(ts,A,A,RHSMatrixHeat,&appctx);
154:   } else if (problem == nonlinear_no_jacobian) {
155:     /*
156:          The user provides the RHS and a Shell Jacobian
157:     */
158:     TSSetRHSFunction(ts,RHSFunctionHeat,&appctx);
159:     MatCreateShell(PETSC_COMM_WORLD,m,appctx.M,appctx.M,appctx.M,&appctx,&A);
160:     MatShellSetOperation(A,MATOP_MULT,(void(*)())RHSMatrixFree);
161:     TSSetRHSJacobian(ts,A,A,PETSC_NULL,&appctx);
162:   } else if (problem == nonlinear) {
163:     /*
164:          The user provides the RHS and Jacobian
165:     */
166:     TSSetRHSFunction(ts,RHSFunctionHeat,&appctx);
167:     MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,appctx.M,appctx.M,&A);
168:     MatSetFromOptions(A);
169:     RHSMatrixHeat(ts,0.0,&A,&A,&A_structure,&appctx);
170:     TSSetRHSJacobian(ts,A,A,RHSJacobianHeat,&appctx);
171:   }

173:   TSSetFromOptions(ts);

175:   TSSetInitialTimeStep(ts,0.0,dt);
176:   TSSetDuration(ts,time_steps,100.);
177:   TSSetSolution(ts,appctx.global);


180:   TSSetUp(ts);
181:   TSStep(ts,&steps,&ftime);
182:   PetscViewerStringOpen(PETSC_COMM_WORLD,tsinfo,120,&viewer);
183:   TSView(ts,viewer);

185:   PetscOptionsHasName(PETSC_NULL,"-test",&flg);
186:   if (flg) {
187:     PetscTruth iseuler;
188:     PetscTypeCompare((PetscObject)ts,"euler",&iseuler);
189:     if (iseuler) {
190:       if (!PETSC_NEAR(appctx.norm_2/steps,0.00257244,1.e-4)) {
191:         fprintf(stdout,"Error in Euler method: 2-norm %g expecting: 0.00257244n",appctx.norm_2/steps);
192:       }
193:     } else {
194:       if (!PETSC_NEAR(appctx.norm_2/steps,0.00506174,1.e-4)) {
195:         fprintf(stdout,"Error in %s method: 2-norm %g expecting: 0.00506174n",tsinfo,appctx.norm_2/steps);
196:       }
197:     }
198:   } else {
199:     PetscPrintf(PETSC_COMM_WORLD,"%d Procs Avg. error 2 norm %g max norm %g %sn",
200:                 size,appctx.norm_2/steps,appctx.norm_max/steps,tsinfo);
201:   }

203:   PetscViewerDestroy(viewer);
204:   TSDestroy(ts);
205:   PetscViewerDestroy(appctx.viewer1);
206:   PetscViewerDestroy(appctx.viewer2);
207:   VecDestroy(appctx.localwork);
208:   VecDestroy(appctx.solution);
209:   VecDestroy(appctx.local);
210:   VecDestroy(appctx.global);
211:   DADestroy(appctx.da);
212:   if (A) {ierr= MatDestroy(A);}

214:   PetscFinalize();
215:   return 0;
216: }

218: /* -------------------------------------------------------------------*/
219: int Initial(Vec global,void *ctx)
220: {
221:   AppCtx *appctx = (AppCtx*) ctx;
222:   Scalar *localptr,h = appctx->h;
223:   int    i,mybase,myend,ierr;

225:   /* determine starting point of each processor */
226:   VecGetOwnershipRange(global,&mybase,&myend);

228:   /* Initialize the array */
229:   VecGetArray(global,&localptr);
230:   for (i=mybase; i<myend; i++) {
231:     localptr[i-mybase] = PetscSinScalar(PETSC_PI*i*6.*h) + 3.*PetscSinScalar(PETSC_PI*i*2.*h);
232:   }
233:   VecRestoreArray(global,&localptr);
234:   return 0;
235: }

237: /*
238:        Exact solution 
239: */
240: int Solution(double t,Vec solution,void *ctx)
241: {
242:   AppCtx *appctx = (AppCtx*) ctx;
243:   Scalar *localptr,h = appctx->h,ex1,ex2,sc1,sc2;
244:   int    i,mybase,myend,ierr;

246:   /* determine starting point of each processor */
247:   VecGetOwnershipRange(solution,&mybase,&myend);

249:   ex1 = PetscExpScalar(-36.*PETSC_PI*PETSC_PI*t);
250:   ex2 = PetscExpScalar(-4.*PETSC_PI*PETSC_PI*t);
251:   sc1 = PETSC_PI*6.*h;                 sc2 = PETSC_PI*2.*h;
252:   VecGetArray(solution,&localptr);
253:   for (i=mybase; i<myend; i++) {
254:     localptr[i-mybase] = PetscSinScalar(sc1*(double)i)*ex1 + 3.*PetscSinScalar(sc2*(double)i)*ex2;
255:   }
256:   VecRestoreArray(solution,&localptr);
257:   return 0;
258: }

260: int Monitor(TS ts,int step,double time,Vec global,void *ctx)
261: {
262:   AppCtx   *appctx = (AppCtx*) ctx;
263:   int      ierr;
264:   double   norm_2,norm_max;
265:   Scalar   mone = -1.0;
266:   MPI_Comm comm;

268:   PetscObjectGetComm((PetscObject)ts,&comm);

270:   VecView(global,appctx->viewer2);

272:   Solution(time,appctx->solution,ctx);
273:   VecAXPY(&mone,global,appctx->solution);
274:   VecNorm(appctx->solution,NORM_2,&norm_2);
275:   norm_2 = sqrt(appctx->h)*norm_2;
276:   VecNorm(appctx->solution,NORM_MAX,&norm_max);

278:   if (!appctx->nox) {
279:     PetscPrintf(comm,"timestep %d time %g norm of error %g %gn",step,time,norm_2,norm_max);
280:   }

282:   appctx->norm_2   += norm_2;
283:   appctx->norm_max += norm_max;

285:   VecView(appctx->solution,appctx->viewer1);

287:   return 0;
288: }

290: /* -----------------------------------------------------------------------*/
291: int RHSMatrixFree(Mat mat,Vec x,Vec y)
292: {
293:   int  ierr;
294:   void *ctx;

296:   MatShellGetContext(mat,(void **)&ctx);
297:   RHSFunctionHeat(0,0.0,x,y,ctx);
298:   return 0;
299: }

301: int RHSFunctionHeat(TS ts,double t,Vec globalin,Vec globalout,void *ctx)
302: {
303:   AppCtx *appctx = (AppCtx*) ctx;
304:   DA     da = appctx->da;
305:   Vec    local = appctx->local,localwork = appctx->localwork;
306:   int    ierr,i,localsize;
307:   Scalar *copyptr,*localptr,sc;

309:   /*Extract local array */
310:   DAGlobalToLocalBegin(da,globalin,INSERT_VALUES,local);
311:   DAGlobalToLocalEnd(da,globalin,INSERT_VALUES,local);
312:   VecGetArray(local,&localptr);

314:   /* Extract work vector */
315:   VecGetArray(localwork,&copyptr);

317:   /* Update Locally - Make array of new values */
318:   /* Note: For the first and last entry I copy the value */
319:   /* if this is an interior node it is irrelevant */
320:   sc = 1.0/(appctx->h*appctx->h);
321:   VecGetLocalSize(local,&localsize);
322:   copyptr[0] = localptr[0];
323:   for (i=1; i<localsize-1; i++) {
324:     copyptr[i] = sc * (localptr[i+1] + localptr[i-1] - 2.0*localptr[i]);
325:   }
326:   copyptr[localsize-1] = localptr[localsize-1];
327:   VecRestoreArray(local,&localptr);
328:   VecRestoreArray(localwork,&copyptr);

330:   /* Local to Global */
331:   DALocalToGlobal(da,localwork,INSERT_VALUES,globalout);
332:   return 0;
333: }

335: /* ---------------------------------------------------------------------*/
336: int RHSMatrixHeat(TS ts,double t,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
337: {
338:   Mat    A = *AA;
339:   AppCtx *appctx = (AppCtx*) ctx;
340:   int    ierr,i,mstart,mend,rank,size,idx[3];
341:   Scalar v[3],stwo = -2./(appctx->h*appctx->h),sone = -.5*stwo;

343:   *str = SAME_NONZERO_PATTERN;

345:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
346:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

348:   MatGetOwnershipRange(A,&mstart,&mend);
349:   if (mstart == 0) {
350:     v[0] = 1.0;
351:     MatSetValues(A,1,&mstart,1,&mstart,v,INSERT_VALUES);
352:     mstart++;
353:   }
354:   if (mend == appctx->M) {
355:     mend--;
356:     v[0] = 1.0;
357:     MatSetValues(A,1,&mend,1,&mend,v,INSERT_VALUES);
358:   }

360:   /*
361:      Construct matrice one row at a time
362:   */
363:   v[0] = sone; v[1] = stwo; v[2] = sone;
364:   for (i=mstart; i<mend; i++) {
365:     idx[0] = i-1; idx[1] = i; idx[2] = i+1;
366:     MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);
367:   }

369:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
370:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
371:   return 0;
372: }

374: int RHSJacobianHeat(TS ts,double t,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
375: {
376:   return RHSMatrixHeat(ts,t,AA,BB,str,ctx);
377: }