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,©ptr);
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,©ptr);
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: }