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: MPI_Comm comm;
281: PetscObjectGetComm((PetscObject)ts,&comm);
283: VecView(global,appctx->viewer2);
285: Solution(ltime,appctx->solution,ctx);
286: VecAXPY(appctx->solution,-1.0,global);
287: VecNorm(appctx->solution,NORM_2,&norm_2);
288: norm_2 = sqrt(appctx->h)*norm_2;
289: VecNorm(appctx->solution,NORM_MAX,&norm_max);
291: if (!appctx->nox) {
292: PetscPrintf(comm,"timestep %D time %G norm of error %G %G\n",step,ltime,norm_2,norm_max);
293: }
295: appctx->norm_2 += norm_2;
296: appctx->norm_max += norm_max;
298: VecView(appctx->solution,appctx->viewer1);
300: return 0;
301: }
303: /* -----------------------------------------------------------------------*/
306: PetscErrorCode RHSMatrixFree(Mat mat,Vec x,Vec y)
307: {
308: PetscErrorCode ierr;
309: void *ctx;
311: MatShellGetContext(mat,(void **)&ctx);
312: RHSFunctionHeat(0,0.0,x,y,ctx);
313: return 0;
314: }
318: PetscErrorCode RHSFunctionHeat(TS ts,PetscReal t,Vec globalin,Vec globalout,void *ctx)
319: {
320: AppCtx *appctx = (AppCtx*) ctx;
321: DA da = appctx->da;
322: Vec local = appctx->local,localwork = appctx->localwork;
324: PetscInt i,localsize;
325: PetscScalar *copyptr,*localptr,sc;
327: /*Extract local array */
328: DAGlobalToLocalBegin(da,globalin,INSERT_VALUES,local);
329: DAGlobalToLocalEnd(da,globalin,INSERT_VALUES,local);
330: VecGetArray(local,&localptr);
332: /* Extract work vector */
333: VecGetArray(localwork,©ptr);
335: /* Update Locally - Make array of new values */
336: /* Note: For the first and last entry I copy the value */
337: /* if this is an interior node it is irrelevant */
338: sc = 1.0/(appctx->h*appctx->h);
339: VecGetLocalSize(local,&localsize);
340: copyptr[0] = localptr[0];
341: for (i=1; i<localsize-1; i++) {
342: copyptr[i] = sc * (localptr[i+1] + localptr[i-1] - 2.0*localptr[i]);
343: }
344: copyptr[localsize-1] = localptr[localsize-1];
345: VecRestoreArray(local,&localptr);
346: VecRestoreArray(localwork,©ptr);
348: /* Local to Global */
349: DALocalToGlobal(da,localwork,INSERT_VALUES,globalout);
350: return 0;
351: }
353: /* ---------------------------------------------------------------------*/
356: PetscErrorCode RHSMatrixHeat(TS ts,PetscReal t,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
357: {
358: Mat A = *AA;
359: AppCtx *appctx = (AppCtx*) ctx;
361: PetscInt i,mstart,mend,idx[3];
362: PetscMPIInt size,rank;
363: PetscScalar v[3],stwo = -2./(appctx->h*appctx->h),sone = -.5*stwo;
365: *str = SAME_NONZERO_PATTERN;
367: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
368: MPI_Comm_size(PETSC_COMM_WORLD,&size);
370: MatGetOwnershipRange(A,&mstart,&mend);
371: if (mstart == 0) {
372: v[0] = 1.0;
373: MatSetValues(A,1,&mstart,1,&mstart,v,INSERT_VALUES);
374: mstart++;
375: }
376: if (mend == appctx->M) {
377: mend--;
378: v[0] = 1.0;
379: MatSetValues(A,1,&mend,1,&mend,v,INSERT_VALUES);
380: }
382: /*
383: Construct matrice one row at a time
384: */
385: v[0] = sone; v[1] = stwo; v[2] = sone;
386: for (i=mstart; i<mend; i++) {
387: idx[0] = i-1; idx[1] = i; idx[2] = i+1;
388: MatSetValues(A,1,&i,3,idx,v,INSERT_VALUES);
389: }
391: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
392: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
393: return 0;
394: }
398: PetscErrorCode RHSJacobianHeat(TS ts,PetscReal t,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
399: {
400: return RHSMatrixHeat(ts,t,AA,BB,str,ctx);
401: }