Actual source code: ex25.c
petsc-dev 2014-02-02
1: static const char help[] = "Time-dependent Brusselator reaction-diffusion PDE in 1d. Demonstrates IMEX methods.\n";
2: /*
3: u_t - alpha u_xx = A + u^2 v - (B+1) u
4: v_t - alpha v_xx = B u - u^2 v
5: 0 < x < 1;
6: A = 1, B = 3, alpha = 1/50
8: Initial conditions:
9: u(x,0) = 1 + sin(2 pi x)
10: v(x,0) = 3
12: Boundary conditions:
13: u(0,t) = u(1,t) = 1
14: v(0,t) = v(1,t) = 3
15: */
17: #include <petscdmda.h>
18: #include <petscts.h>
20: typedef struct {
21: PetscScalar u,v;
22: } Field;
24: typedef struct _User *User;
25: struct _User {
26: PetscReal A,B; /* Reaction coefficients */
27: PetscReal alpha; /* Diffusion coefficient */
28: PetscReal uleft,uright; /* Dirichlet boundary conditions */
29: PetscReal vleft,vright; /* Dirichlet boundary conditions */
30: };
32: static PetscErrorCode FormRHSFunction(TS,PetscReal,Vec,Vec,void*);
33: static PetscErrorCode FormIFunction(TS,PetscReal,Vec,Vec,Vec,void*);
34: static PetscErrorCode FormIJacobian(TS,PetscReal,Vec,Vec,PetscReal,Mat*,Mat*,MatStructure*,void*);
35: static PetscErrorCode FormInitialSolution(TS,Vec,void*);
39: int main(int argc,char **argv)
40: {
41: TS ts; /* nonlinear solver */
42: Vec X; /* solution, residual vectors */
43: Mat J; /* Jacobian matrix */
44: PetscInt steps,maxsteps,mx;
45: PetscErrorCode ierr;
46: DM da;
47: PetscReal ftime,hx,dt;
48: struct _User user; /* user-defined work context */
49: TSConvergedReason reason;
51: PetscInitialize(&argc,&argv,(char*)0,help);
53: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54: Create distributed array (DMDA) to manage parallel grid and vectors
55: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
56: DMDACreate1d(PETSC_COMM_WORLD,DMDA_BOUNDARY_NONE,-11,2,2,NULL,&da);
58: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
59: Extract global vectors from DMDA;
60: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
61: DMCreateGlobalVector(da,&X);
63: /* Initialize user application context */
64: PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Advection-reaction options","");
65: {
66: user.A = 1;
67: user.B = 3;
68: user.alpha = 0.02;
69: user.uleft = 1;
70: user.uright = 1;
71: user.vleft = 3;
72: user.vright = 3;
73: PetscOptionsReal("-A","Reaction rate","",user.A,&user.A,NULL);
74: PetscOptionsReal("-B","Reaction rate","",user.B,&user.B,NULL);
75: PetscOptionsReal("-alpha","Diffusion coefficient","",user.alpha,&user.alpha,NULL);
76: PetscOptionsReal("-uleft","Dirichlet boundary condition","",user.uleft,&user.uleft,NULL);
77: PetscOptionsReal("-uright","Dirichlet boundary condition","",user.uright,&user.uright,NULL);
78: PetscOptionsReal("-vleft","Dirichlet boundary condition","",user.vleft,&user.vleft,NULL);
79: PetscOptionsReal("-vright","Dirichlet boundary condition","",user.vright,&user.vright,NULL);
80: }
81: PetscOptionsEnd();
83: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84: Create timestepping solver context
85: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
86: TSCreate(PETSC_COMM_WORLD,&ts);
87: TSSetDM(ts,da);
88: TSSetType(ts,TSARKIMEX);
89: TSSetRHSFunction(ts,NULL,FormRHSFunction,&user);
90: TSSetIFunction(ts,NULL,FormIFunction,&user);
91: DMSetMatType(da,MATAIJ);
92: DMCreateMatrix(da,&J);
93: TSSetIJacobian(ts,J,J,FormIJacobian,&user);
95: ftime = 10.0;
96: maxsteps = 10000;
97: TSSetDuration(ts,maxsteps,ftime);
99: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100: Set initial conditions
101: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102: FormInitialSolution(ts,X,&user);
103: TSSetSolution(ts,X);
104: VecGetSize(X,&mx);
105: hx = 1.0/(PetscReal)(mx/2-1);
106: dt = 0.4 * PetscSqr(hx) / user.alpha; /* Diffusive stability limit */
107: TSSetInitialTimeStep(ts,0.0,dt);
109: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110: Set runtime options
111: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
112: TSSetFromOptions(ts);
114: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
115: Solve nonlinear system
116: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
117: TSSolve(ts,X);
118: TSGetSolveTime(ts,&ftime);
119: TSGetTimeStepNumber(ts,&steps);
120: TSGetConvergedReason(ts,&reason);
121: PetscPrintf(PETSC_COMM_WORLD,"%s at time %g after %D steps\n",TSConvergedReasons[reason],(double)ftime,steps);
123: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124: Free work space.
125: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
126: MatDestroy(&J);
127: VecDestroy(&X);
128: TSDestroy(&ts);
129: DMDestroy(&da);
130: PetscFinalize();
131: return 0;
132: }
136: static PetscErrorCode FormIFunction(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void *ptr)
137: {
138: User user = (User)ptr;
139: DM da;
140: DMDALocalInfo info;
141: PetscInt i;
142: Field *x,*xdot,*f;
143: PetscReal hx;
144: Vec Xloc;
148: TSGetDM(ts,&da);
149: DMDAGetLocalInfo(da,&info);
150: hx = 1.0/(PetscReal)(info.mx-1);
152: /*
153: Scatter ghost points to local vector,using the 2-step process
154: DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
155: By placing code between these two statements, computations can be
156: done while messages are in transition.
157: */
158: DMGetLocalVector(da,&Xloc);
159: DMGlobalToLocalBegin(da,X,INSERT_VALUES,Xloc);
160: DMGlobalToLocalEnd(da,X,INSERT_VALUES,Xloc);
162: /* Get pointers to vector data */
163: DMDAVecGetArray(da,Xloc,&x);
164: DMDAVecGetArray(da,Xdot,&xdot);
165: DMDAVecGetArray(da,F,&f);
167: /* Compute function over the locally owned part of the grid */
168: for (i=info.xs; i<info.xs+info.xm; i++) {
169: if (i == 0) {
170: f[i].u = hx * (x[i].u - user->uleft);
171: f[i].v = hx * (x[i].v - user->vleft);
172: } else if (i == info.mx-1) {
173: f[i].u = hx * (x[i].u - user->uright);
174: f[i].v = hx * (x[i].v - user->vright);
175: } else {
176: f[i].u = hx * xdot[i].u - user->alpha * (x[i-1].u - 2.*x[i].u + x[i+1].u) / hx;
177: f[i].v = hx * xdot[i].v - user->alpha * (x[i-1].v - 2.*x[i].v + x[i+1].v) / hx;
178: }
179: }
181: /* Restore vectors */
182: DMDAVecRestoreArray(da,Xloc,&x);
183: DMDAVecRestoreArray(da,Xdot,&xdot);
184: DMDAVecRestoreArray(da,F,&f);
185: DMRestoreLocalVector(da,&Xloc);
186: return(0);
187: }
191: static PetscErrorCode FormRHSFunction(TS ts,PetscReal t,Vec X,Vec F,void *ptr)
192: {
193: User user = (User)ptr;
194: DM da;
195: DMDALocalInfo info;
196: PetscInt i;
197: PetscReal hx;
198: Field *x,*f;
202: TSGetDM(ts,&da);
203: DMDAGetLocalInfo(da,&info);
204: hx = 1.0/(PetscReal)(info.mx-1);
206: /* Get pointers to vector data */
207: DMDAVecGetArray(da,X,&x);
208: DMDAVecGetArray(da,F,&f);
210: /* Compute function over the locally owned part of the grid */
211: for (i=info.xs; i<info.xs+info.xm; i++) {
212: PetscScalar u = x[i].u,v = x[i].v;
213: f[i].u = hx*(user->A + u*u*v - (user->B+1)*u);
214: f[i].v = hx*(user->B*u - u*u*v);
215: }
217: /* Restore vectors */
218: DMDAVecRestoreArray(da,X,&x);
219: DMDAVecRestoreArray(da,F,&f);
220: return(0);
221: }
223: /* --------------------------------------------------------------------- */
224: /*
225: IJacobian - Compute IJacobian = dF/dU + a dF/dUdot
226: */
229: PetscErrorCode FormIJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat *J,Mat *Jpre,MatStructure *str,void *ptr)
230: {
231: User user = (User)ptr;
233: DMDALocalInfo info;
234: PetscInt i;
235: PetscReal hx;
236: DM da;
237: Field *x,*xdot;
240: TSGetDM(ts,&da);
241: DMDAGetLocalInfo(da,&info);
242: hx = 1.0/(PetscReal)(info.mx-1);
244: /* Get pointers to vector data */
245: DMDAVecGetArray(da,X,&x);
246: DMDAVecGetArray(da,Xdot,&xdot);
248: /* Compute function over the locally owned part of the grid */
249: for (i=info.xs; i<info.xs+info.xm; i++) {
250: if (i == 0 || i == info.mx-1) {
251: const PetscInt row = i,col = i;
252: const PetscScalar vals[2][2] = {{hx,0},{0,hx}};
253: MatSetValuesBlocked(*Jpre,1,&row,1,&col,&vals[0][0],INSERT_VALUES);
254: } else {
255: const PetscInt row = i,col[] = {i-1,i,i+1};
256: const PetscScalar dxxL = -user->alpha/hx,dxx0 = 2.*user->alpha/hx,dxxR = -user->alpha/hx;
257: const PetscScalar vals[2][3][2] = {{{dxxL,0},{a *hx+dxx0,0},{dxxR,0}},
258: {{0,dxxL},{0,a*hx+dxx0},{0,dxxR}}};
259: MatSetValuesBlocked(*Jpre,1,&row,3,col,&vals[0][0][0],INSERT_VALUES);
260: }
261: }
263: /* Restore vectors */
264: DMDAVecRestoreArray(da,X,&x);
265: DMDAVecRestoreArray(da,Xdot,&xdot);
267: MatAssemblyBegin(*Jpre,MAT_FINAL_ASSEMBLY);
268: MatAssemblyEnd(*Jpre,MAT_FINAL_ASSEMBLY);
269: if (*J != *Jpre) {
270: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
271: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
272: }
273: return(0);
274: }
278: PetscErrorCode FormInitialSolution(TS ts,Vec X,void *ctx)
279: {
280: User user = (User)ctx;
281: DM da;
282: PetscInt i;
283: DMDALocalInfo info;
284: Field *x;
285: PetscReal hx;
289: TSGetDM(ts,&da);
290: DMDAGetLocalInfo(da,&info);
291: hx = 1.0/(PetscReal)(info.mx-1);
293: /* Get pointers to vector data */
294: DMDAVecGetArray(da,X,&x);
296: /* Compute function over the locally owned part of the grid */
297: for (i=info.xs; i<info.xs+info.xm; i++) {
298: PetscReal xi = i*hx;
299: x[i].u = user->uleft*(1.-xi) + user->uright*xi + PetscSinReal(2.*PETSC_PI*xi);
300: x[i].v = user->vleft*(1.-xi) + user->vright*xi;
301: }
302: DMDAVecRestoreArray(da,X,&x);
303: return(0);
304: }