Actual source code: beuler.c
1: /*$Id: beuler.c,v 1.61 2001/09/11 16:34:19 bsmith Exp $*/
2: /*
3: Code for Timestepping with implicit backwards Euler.
4: */
5: #include src/ts/tsimpl.h
7: typedef struct {
8: Vec update; /* work vector where new solution is formed */
9: Vec func; /* work vector where F(t[i],u[i]) is stored */
10: Vec rhs; /* work vector for RHS; vec_sol/dt */
11: } TS_BEuler;
13: /*------------------------------------------------------------------------------*/
15: /*
16: Version for linear PDE where RHS does not depend on time. Has built a
17: single matrix that is to be used for all timesteps.
18: */
19: #undef __FUNCT__
21: static int TSStep_BEuler_Linear_Constant_Matrix(TS ts,int *steps,PetscReal *ptime)
22: {
23: TS_BEuler *beuler = (TS_BEuler*)ts->data;
24: Vec sol = ts->vec_sol,update = beuler->update;
25: Vec rhs = beuler->rhs;
26: int ierr,i,max_steps = ts->max_steps,its;
27: PetscScalar mdt = 1.0/ts->time_step;
28:
30: *steps = -ts->steps;
31: TSMonitor(ts,ts->steps,ts->ptime,sol);
33: /* set initial guess to be previous solution */
34: VecCopy(sol,update);
36: for (i=0; i<max_steps; i++) {
37: VecCopy(sol,rhs);
38: VecScale(&mdt,rhs);
39: /* apply user-provided boundary conditions (only needed if they are time dependent) */
40: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
42: ts->ptime += ts->time_step;
43: if (ts->ptime > ts->max_time) break;
44: SLESSolve(ts->sles,rhs,update,&its);
45: ts->linear_its += its;
46: VecCopy(update,sol);
47: ts->steps++;
48: TSMonitor(ts,ts->steps,ts->ptime,sol);
49: }
51: *steps += ts->steps;
52: *ptime = ts->ptime;
53: return(0);
54: }
55: /*
56: Version where matrix depends on time
57: */
58: #undef __FUNCT__
60: static int TSStep_BEuler_Linear_Variable_Matrix(TS ts,int *steps,PetscReal *ptime)
61: {
62: TS_BEuler *beuler = (TS_BEuler*)ts->data;
63: Vec sol = ts->vec_sol,update = beuler->update,rhs = beuler->rhs;
64: int ierr,i,max_steps = ts->max_steps,its;
65: PetscScalar mdt = 1.0/ts->time_step,mone = -1.0;
66: MatStructure str;
69: *steps = -ts->steps;
70: TSMonitor(ts,ts->steps,ts->ptime,sol);
72: /* set initial guess to be previous solution */
73: VecCopy(sol,update);
75: for (i=0; i<max_steps; i++) {
76: VecCopy(sol,rhs);
77: VecScale(&mdt,rhs);
78: /* apply user-provided boundary conditions (only needed if they are time dependent) */
79: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
81: ts->ptime += ts->time_step;
82: if (ts->ptime > ts->max_time) break;
83: /*
84: evaluate matrix function
85: */
86: (*ts->ops->rhsmatrix)(ts,ts->ptime,&ts->A,&ts->B,&str,ts->jacP);
87: MatScale(&mone,ts->A);
88: MatShift(&mdt,ts->A);
89: if (ts->B != ts->A && str != SAME_PRECONDITIONER) {
90: MatScale(&mone,ts->B);
91: MatShift(&mdt,ts->B);
92: }
93: SLESSetOperators(ts->sles,ts->A,ts->B,str);
94: SLESSolve(ts->sles,rhs,update,&its);
95: ts->linear_its += its;
96: VecCopy(update,sol);
97: ts->steps++;
98: TSMonitor(ts,ts->steps,ts->ptime,sol);
99: }
101: *steps += ts->steps;
102: *ptime = ts->ptime;
103: return(0);
104: }
105: /*
106: Version for nonlinear PDE.
107: */
108: #undef __FUNCT__
110: static int TSStep_BEuler_Nonlinear(TS ts,int *steps,PetscReal *ptime)
111: {
112: Vec sol = ts->vec_sol;
113: int ierr,i,max_steps = ts->max_steps,its,lits;
114: TS_BEuler *beuler = (TS_BEuler*)ts->data;
115:
117: *steps = -ts->steps;
118: TSMonitor(ts,ts->steps,ts->ptime,sol);
120: for (i=0; i<max_steps; i++) {
121: ts->ptime += ts->time_step;
122: if (ts->ptime > ts->max_time) break;
123: VecCopy(sol,beuler->update);
124: SNESSolve(ts->snes,beuler->update,&its);
125: SNESGetNumberLinearIterations(ts->snes,&lits);
126: ts->nonlinear_its += its; ts->linear_its += lits;
127: VecCopy(beuler->update,sol);
128: ts->steps++;
129: TSMonitor(ts,ts->steps,ts->ptime,sol);
130: }
132: *steps += ts->steps;
133: *ptime = ts->ptime;
134: return(0);
135: }
137: /*------------------------------------------------------------*/
138: #undef __FUNCT__
140: static int TSDestroy_BEuler(TS ts)
141: {
142: TS_BEuler *beuler = (TS_BEuler*)ts->data;
143: int ierr;
146: if (beuler->update) {VecDestroy(beuler->update);}
147: if (beuler->func) {VecDestroy(beuler->func);}
148: if (beuler->rhs) {VecDestroy(beuler->rhs);}
149: PetscFree(beuler);
150: return(0);
151: }
155: /*
156: This defines the nonlinear equation that is to be solved with SNES
158: U^{n+1} - dt*F(U^{n+1}) - U^{n}
159: */
160: #undef __FUNCT__
162: int TSBEulerFunction(SNES snes,Vec x,Vec y,void *ctx)
163: {
164: TS ts = (TS) ctx;
165: PetscScalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
166: int ierr,i,n;
169: /* apply user-provided function */
170: TSComputeRHSFunction(ts,ts->ptime,x,y);
171: /* (u^{n+1} - U^{n})/dt - F(u^{n+1}) */
172: VecGetArray(ts->vec_sol,&un);
173: VecGetArray(x,&unp1);
174: VecGetArray(y,&Funp1);
175: VecGetLocalSize(x,&n);
177: for (i=0; i<n; i++) {
178: Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
179: }
180: VecRestoreArray(ts->vec_sol,&un);
181: VecRestoreArray(x,&unp1);
182: VecRestoreArray(y,&Funp1);
183: return(0);
184: }
186: /*
187: This constructs the Jacobian needed for SNES
189: J = I/dt - J_{F} where J_{F} is the given Jacobian of F.
190: */
191: #undef __FUNCT__
193: int TSBEulerJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
194: {
195: TS ts = (TS) ctx;
196: int ierr;
197: PetscScalar mone = -1.0,mdt = 1.0/ts->time_step;
200: /* construct user's Jacobian */
201: TSComputeRHSJacobian(ts,ts->ptime,x,AA,BB,str);
203: /* shift and scale Jacobian */
204: MatScale(&mone,*AA);
205: MatShift(&mdt,*AA);
206: if (*BB != *AA && *str != SAME_PRECONDITIONER) {
207: MatScale(&mone,*BB);
208: MatShift(&mdt,*BB);
209: }
211: return(0);
212: }
214: /* ------------------------------------------------------------*/
215: #undef __FUNCT__
217: static int TSSetUp_BEuler_Linear_Constant_Matrix(TS ts)
218: {
219: TS_BEuler *beuler = (TS_BEuler*)ts->data;
220: int ierr;
221: PetscScalar mdt = 1.0/ts->time_step,mone = -1.0;
224: SLESSetFromOptions(ts->sles);
225: VecDuplicate(ts->vec_sol,&beuler->update);
226: VecDuplicate(ts->vec_sol,&beuler->rhs);
227:
228: /* build linear system to be solved */
229: MatScale(&mone,ts->A);
230: MatShift(&mdt,ts->A);
231: if (ts->A != ts->B) {
232: MatScale(&mone,ts->B);
233: MatShift(&mdt,ts->B);
234: }
235: SLESSetOperators(ts->sles,ts->A,ts->B,SAME_NONZERO_PATTERN);
236: return(0);
237: }
239: #undef __FUNCT__
241: static int TSSetUp_BEuler_Linear_Variable_Matrix(TS ts)
242: {
243: TS_BEuler *beuler = (TS_BEuler*)ts->data;
244: int ierr;
247: SLESSetFromOptions(ts->sles);
248: VecDuplicate(ts->vec_sol,&beuler->update);
249: VecDuplicate(ts->vec_sol,&beuler->rhs);
250: return(0);
251: }
253: #undef __FUNCT__
255: static int TSSetUp_BEuler_Nonlinear(TS ts)
256: {
257: TS_BEuler *beuler = (TS_BEuler*)ts->data;
258: int ierr;
261: VecDuplicate(ts->vec_sol,&beuler->update);
262: VecDuplicate(ts->vec_sol,&beuler->func);
263: SNESSetFunction(ts->snes,beuler->func,TSBEulerFunction,ts);
264: SNESSetJacobian(ts->snes,ts->A,ts->B,TSBEulerJacobian,ts);
265: return(0);
266: }
267: /*------------------------------------------------------------*/
269: #undef __FUNCT__
271: static int TSSetFromOptions_BEuler_Linear(TS ts)
272: {
274:
275: return(0);
276: }
278: #undef __FUNCT__
280: static int TSSetFromOptions_BEuler_Nonlinear(TS ts)
281: {
283:
284: return(0);
285: }
287: #undef __FUNCT__
289: static int TSView_BEuler(TS ts,PetscViewer viewer)
290: {
292: return(0);
293: }
295: /* ------------------------------------------------------------ */
296: EXTERN_C_BEGIN
297: #undef __FUNCT__
299: int TSCreate_BEuler(TS ts)
300: {
301: TS_BEuler *beuler;
302: int ierr;
303: KSP ksp;
306: ts->ops->destroy = TSDestroy_BEuler;
307: ts->ops->view = TSView_BEuler;
309: if (ts->problem_type == TS_LINEAR) {
310: if (!ts->A) {
311: SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set rhs matrix for linear problem");
312: }
313: if (!ts->ops->rhsmatrix) {
314: ts->ops->setup = TSSetUp_BEuler_Linear_Constant_Matrix;
315: ts->ops->step = TSStep_BEuler_Linear_Constant_Matrix;
316: } else {
317: ts->ops->setup = TSSetUp_BEuler_Linear_Variable_Matrix;
318: ts->ops->step = TSStep_BEuler_Linear_Variable_Matrix;
319: }
320: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Linear;
321: SLESCreate(ts->comm,&ts->sles);
322: SLESGetKSP(ts->sles,&ksp);
323: KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);
324: } else if (ts->problem_type == TS_NONLINEAR) {
325: ts->ops->setup = TSSetUp_BEuler_Nonlinear;
326: ts->ops->step = TSStep_BEuler_Nonlinear;
327: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Nonlinear;
328: SNESCreate(ts->comm,&ts->snes);
329: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"No such problem");
331: PetscNew(TS_BEuler,&beuler);
332: PetscLogObjectMemory(ts,sizeof(TS_BEuler));
333: ierr = PetscMemzero(beuler,sizeof(TS_BEuler));
334: ts->data = (void*)beuler;
336: return(0);
337: }
338: EXTERN_C_END