Actual source code: ex1.c

  1: /*
  2:        Formatted test for TS routines.

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

  9: static char help[] = "Solves 1D heat equation.\n\n";

 11:  #include petscda.h
 12:  #include petscsys.h
 13:  #include petscts.h

 15: #define PETSC_NEAR(a,b,c) (!(PetscAbsReal((a)-(b)) > (c)*PetscMax(PetscAbsReal(a),PetscAbsReal(b))))

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


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

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

 62:   appctx.M = 60;
 63:   PetscOptionsGetInt(PETSC_NULL,"-M",&appctx.M,PETSC_NULL);
 64:   PetscOptionsGetInt(PETSC_NULL,"-time",&time_steps,PETSC_NULL);
 65: 
 66:   PetscOptionsHasName(PETSC_NULL,"-nox",&appctx.nox);
 67:   appctx.norm_2 = 0.0; appctx.norm_max = 0.0;

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

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

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


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

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

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

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

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

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

179:   TSSetFromOptions(ts);

181:   TSSetInitialTimeStep(ts,0.0,dt);
182:   TSSetDuration(ts,time_steps,100.);
183:   TSSetSolution(ts,appctx.global);


186:   TSSetUp(ts);
187:   TSStep(ts,&steps,&ftime);
188:   PetscViewerStringOpen(PETSC_COMM_WORLD,tsinfo,120,&viewer);
189:   TSView(ts,viewer);

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

209:   PetscViewerDestroy(viewer);
210:   TSDestroy(ts);
211:   PetscViewerDestroy(appctx.viewer1);
212:   PetscViewerDestroy(appctx.viewer2);
213:   VecDestroy(appctx.localwork);
214:   VecDestroy(appctx.solution);
215:   VecDestroy(appctx.local);
216:   VecDestroy(appctx.global);
217:   DADestroy(appctx.da);
218:   if (A) {ierr= MatDestroy(A);}

220:   PetscFinalize();
221:   return 0;
222: }

224: /* -------------------------------------------------------------------*/
227: PetscErrorCode Initial(Vec global,void *ctx)
228: {
229:   AppCtx         *appctx = (AppCtx*) ctx;
230:   PetscScalar    *localptr,h = appctx->h;
231:   PetscInt       i,mybase,myend;

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

237:   /* Initialize the array */
238:   VecGetArray(global,&localptr);
239:   for (i=mybase; i<myend; i++) {
240:     localptr[i-mybase] = PetscSinScalar(PETSC_PI*i*6.*h) + 3.*PetscSinScalar(PETSC_PI*i*2.*h);
241:   }
242:   VecRestoreArray(global,&localptr);
243:   return 0;
244: }

248: /*
249:        Exact solution 
250: */
251: PetscErrorCode Solution(PetscReal t,Vec solution,void *ctx)
252: {
253:   AppCtx *       appctx = (AppCtx*) ctx;
254:   PetscScalar    *localptr,h = appctx->h,ex1,ex2,sc1,sc2;
255:   PetscInt       i,mybase,myend;

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

261:   ex1 = exp(-36.*PETSC_PI*PETSC_PI*t);
262:   ex2 = exp(-4.*PETSC_PI*PETSC_PI*t);
263:   sc1 = PETSC_PI*6.*h;                 sc2 = PETSC_PI*2.*h;
264:   VecGetArray(solution,&localptr);
265:   for (i=mybase; i<myend; i++) {
266:     localptr[i-mybase] = PetscSinScalar(sc1*(PetscReal)i)*ex1 + 3.*PetscSinScalar(sc2*(PetscReal)i)*ex2;
267:   }
268:   VecRestoreArray(solution,&localptr);
269:   return 0;
270: }

274: PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal ltime,Vec global,void *ctx)
275: {
276:   AppCtx         *appctx = (AppCtx*) ctx;
278:   PetscReal      norm_2,norm_max;
279:   PetscScalar    mone = -1.0;
280:   MPI_Comm       comm;

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

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

286:   Solution(ltime,appctx->solution,ctx);
287:   VecAXPY(appctx->solution,mone,global);
288:   VecNorm(appctx->solution,NORM_2,&norm_2);
289:   norm_2 = sqrt(appctx->h)*norm_2;
290:   VecNorm(appctx->solution,NORM_MAX,&norm_max);

292:   if (!appctx->nox) {
293:     PetscPrintf(comm,"timestep %D time %g norm of error %g %g\n",step,ltime,norm_2,norm_max);
294:   }

296:   appctx->norm_2   += norm_2;
297:   appctx->norm_max += norm_max;

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

301:   return 0;
302: }

304: /* -----------------------------------------------------------------------*/
307: PetscErrorCode RHSMatrixFree(Mat mat,Vec x,Vec y)
308: {
309:   PetscErrorCode  ierr;
310:   void            *ctx;

312:   MatShellGetContext(mat,(void **)&ctx);
313:   RHSFunctionHeat(0,0.0,x,y,ctx);
314:   return 0;
315: }

319: PetscErrorCode RHSFunctionHeat(TS ts,PetscReal t,Vec globalin,Vec globalout,void *ctx)
320: {
321:   AppCtx         *appctx = (AppCtx*) ctx;
322:   DA             da = appctx->da;
323:   Vec            local = appctx->local,localwork = appctx->localwork;
325:   PetscInt       i,localsize;
326:   PetscScalar    *copyptr,*localptr,sc;

328:   /*Extract local array */
329:   DAGlobalToLocalBegin(da,globalin,INSERT_VALUES,local);
330:   DAGlobalToLocalEnd(da,globalin,INSERT_VALUES,local);
331:   VecGetArray(local,&localptr);

333:   /* Extract work vector */
334:   VecGetArray(localwork,&copyptr);

336:   /* Update Locally - Make array of new values */
337:   /* Note: For the first and last entry I copy the value */
338:   /* if this is an interior node it is irrelevant */
339:   sc = 1.0/(appctx->h*appctx->h);
340:   VecGetLocalSize(local,&localsize);
341:   copyptr[0] = localptr[0];
342:   for (i=1; i<localsize-1; i++) {
343:     copyptr[i] = sc * (localptr[i+1] + localptr[i-1] - 2.0*localptr[i]);
344:   }
345:   copyptr[localsize-1] = localptr[localsize-1];
346:   VecRestoreArray(local,&localptr);
347:   VecRestoreArray(localwork,&copyptr);

349:   /* Local to Global */
350:   DALocalToGlobal(da,localwork,INSERT_VALUES,globalout);
351:   return 0;
352: }

354: /* ---------------------------------------------------------------------*/
357: PetscErrorCode RHSMatrixHeat(TS ts,PetscReal t,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
358: {
359:   Mat            A = *AA;
360:   AppCtx         *appctx = (AppCtx*) ctx;
362:   PetscInt       i,mstart,mend,idx[3];
363:   PetscMPIInt    size,rank;
364:   PetscScalar    v[3],stwo = -2./(appctx->h*appctx->h),sone = -.5*stwo;

366:   *str = SAME_NONZERO_PATTERN;

368:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
369:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

371:   MatGetOwnershipRange(A,&mstart,&mend);
372:   if (mstart == 0) {
373:     v[0] = 1.0;
374:     MatSetValues(A,1,&mstart,1,&mstart,v,INSERT_VALUES);
375:     mstart++;
376:   }
377:   if (mend == appctx->M) {
378:     mend--;
379:     v[0] = 1.0;
380:     MatSetValues(A,1,&mend,1,&mend,v,INSERT_VALUES);
381:   }

383:   /*
384:      Construct matrice one row at a time
385:   */
386:   v[0] = sone; v[1] = stwo; v[2] = sone;
387:   for (i=mstart; i<mend; i++) {
388:     idx[0] = i-1; idx[1] = i; idx[2] = i+1;
389:     MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);
390:   }

392:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
393:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
394:   return 0;
395: }

399: PetscErrorCode RHSJacobianHeat(TS ts,PetscReal t,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
400: {
401:   return RHSMatrixHeat(ts,t,AA,BB,str,ctx);
402: }