Actual source code: beuler.c
1: /*$Id: beuler.c,v 1.56 2001/04/04 16:56:38 balay Exp $*/
2: /*
3: Code for Timestepping with implicit backwards Euler.
4: */
5: #include "src/ts/tsimpl.h" /*I "petscts.h" I*/
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: static int TSStep_BEuler_Linear_Constant_Matrix(TS ts,int *steps,double *ptime)
20: {
21: TS_BEuler *beuler = (TS_BEuler*)ts->data;
22: Vec sol = ts->vec_sol,update = beuler->update;
23: Vec rhs = beuler->rhs;
24: int ierr,i,max_steps = ts->max_steps,its;
25: Scalar mdt = 1.0/ts->time_step;
26:
28: *steps = -ts->steps;
29: TSMonitor(ts,ts->steps,ts->ptime,sol);
31: /* set initial guess to be previous solution */
32: VecCopy(sol,update);
34: for (i=0; i<max_steps; i++) {
35: VecCopy(sol,rhs);
36: VecScale(&mdt,rhs);
37: /* apply user-provided boundary conditions (only needed if they are time dependent) */
38: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
40: ts->ptime += ts->time_step;
41: if (ts->ptime > ts->max_time) break;
42: SLESSolve(ts->sles,rhs,update,&its);
43: ts->linear_its += its;
44: VecCopy(update,sol);
45: ts->steps++;
46: TSMonitor(ts,ts->steps,ts->ptime,sol);
47: }
49: *steps += ts->steps;
50: *ptime = ts->ptime;
51: return(0);
52: }
53: /*
54: Version where matrix depends on time
55: */
56: static int TSStep_BEuler_Linear_Variable_Matrix(TS ts,int *steps,double *ptime)
57: {
58: TS_BEuler *beuler = (TS_BEuler*)ts->data;
59: Vec sol = ts->vec_sol,update = beuler->update,rhs = beuler->rhs;
60: int ierr,i,max_steps = ts->max_steps,its;
61: Scalar mdt = 1.0/ts->time_step,mone = -1.0;
62: MatStructure str;
65: *steps = -ts->steps;
66: TSMonitor(ts,ts->steps,ts->ptime,sol);
68: /* set initial guess to be previous solution */
69: VecCopy(sol,update);
71: for (i=0; i<max_steps; i++) {
72: VecCopy(sol,rhs);
73: VecScale(&mdt,rhs);
74: /* apply user-provided boundary conditions (only needed if they are time dependent) */
75: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
77: ts->ptime += ts->time_step;
78: if (ts->ptime > ts->max_time) break;
79: /*
80: evaluate matrix function
81: */
82: (*ts->rhsmatrix)(ts,ts->ptime,&ts->A,&ts->B,&str,ts->jacP);
83: if (!ts->Ashell) {
84: MatScale(&mone,ts->A);
85: MatShift(&mdt,ts->A);
86: }
87: if (ts->B != ts->A && ts->Ashell != ts->B && str != SAME_PRECONDITIONER) {
88: MatScale(&mone,ts->B);
89: MatShift(&mdt,ts->B);
90: }
91: SLESSetOperators(ts->sles,ts->A,ts->B,str);
92: SLESSolve(ts->sles,rhs,update,&its);
93: ts->linear_its += its;
94: VecCopy(update,sol);
95: ts->steps++;
96: TSMonitor(ts,ts->steps,ts->ptime,sol);
97: }
99: *steps += ts->steps;
100: *ptime = ts->ptime;
101: return(0);
102: }
103: /*
104: Version for nonlinear PDE.
105: */
106: static int TSStep_BEuler_Nonlinear(TS ts,int *steps,double *ptime)
107: {
108: Vec sol = ts->vec_sol;
109: int ierr,i,max_steps = ts->max_steps,its,lits;
110: TS_BEuler *beuler = (TS_BEuler*)ts->data;
111:
113: *steps = -ts->steps;
114: TSMonitor(ts,ts->steps,ts->ptime,sol);
116: for (i=0; i<max_steps; i++) {
117: ts->ptime += ts->time_step;
118: if (ts->ptime > ts->max_time) break;
119: VecCopy(sol,beuler->update);
120: SNESSolve(ts->snes,beuler->update,&its);
121: SNESGetNumberLinearIterations(ts->snes,&lits);
122: ts->nonlinear_its += its; ts->linear_its += lits;
123: VecCopy(beuler->update,sol);
124: ts->steps++;
125: TSMonitor(ts,ts->steps,ts->ptime,sol);
126: }
128: *steps += ts->steps;
129: *ptime = ts->ptime;
130: return(0);
131: }
133: /*------------------------------------------------------------*/
134: static int TSDestroy_BEuler(TS ts)
135: {
136: TS_BEuler *beuler = (TS_BEuler*)ts->data;
137: int ierr;
140: if (beuler->update) {VecDestroy(beuler->update);}
141: if (beuler->func) {VecDestroy(beuler->func);}
142: if (beuler->rhs) {VecDestroy(beuler->rhs);}
143: if (ts->Ashell) {MatDestroy(ts->A);}
144: PetscFree(beuler);
145: return(0);
146: }
149: /*------------------------------------------------------------*/
150: /*
151: This matrix shell multiply where user provided Shell matrix
152: */
154: int TSBEulerMatMult(Mat mat,Vec x,Vec y)
155: {
156: TS ts;
157: Scalar mdt,mone = -1.0;
158: int ierr;
161: MatShellGetContext(mat,(void **)&ts);
162: mdt = 1.0/ts->time_step;
164: /* apply user provided function */
165: MatMult(ts->Ashell,x,y);
166: /* shift and scale by 1/dt - F */
167: VecAXPBY(&mdt,&mone,x,y);
168: return(0);
169: }
171: /*
172: This defines the nonlinear equation that is to be solved with SNES
174: U^{n+1} - dt*F(U^{n+1}) - U^{n}
175: */
176: int TSBEulerFunction(SNES snes,Vec x,Vec y,void *ctx)
177: {
178: TS ts = (TS) ctx;
179: Scalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
180: int ierr,i,n;
183: /* apply user-provided function */
184: TSComputeRHSFunction(ts,ts->ptime,x,y);
185: /* (u^{n+1} - U^{n})/dt - F(u^{n+1}) */
186: VecGetArray(ts->vec_sol,&un);
187: VecGetArray(x,&unp1);
188: VecGetArray(y,&Funp1);
189: VecGetLocalSize(x,&n);
191: for (i=0; i<n; i++) {
192: Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
193: }
194: VecRestoreArray(ts->vec_sol,&un);
195: VecRestoreArray(x,&unp1);
196: VecRestoreArray(y,&Funp1);
197: return(0);
198: }
200: /*
201: This constructs the Jacobian needed for SNES
203: J = I/dt - J_{F} where J_{F} is the given Jacobian of F.
204: */
205: int TSBEulerJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
206: {
207: TS ts = (TS) ctx;
208: int ierr;
209: Scalar mone = -1.0,mdt = 1.0/ts->time_step;
210: PetscTruth isshell;
213: /* construct user's Jacobian */
214: TSComputeRHSJacobian(ts,ts->ptime,x,AA,BB,str);
216: /* shift and scale Jacobian, if not matrix-free */
217: PetscTypeCompare((PetscObject)*AA,MATSHELL,&isshell);
218: if (!isshell) {
219: MatScale(&mone,*AA);
220: MatShift(&mdt,*AA);
221: }
222: PetscTypeCompare((PetscObject)*BB,MATSHELL,&isshell);
223: if (*BB != *AA && *str != SAME_PRECONDITIONER && !isshell) {
224: MatScale(&mone,*BB);
225: MatShift(&mdt,*BB);
226: }
228: return(0);
229: }
231: /* ------------------------------------------------------------*/
232: static int TSSetUp_BEuler_Linear_Constant_Matrix(TS ts)
233: {
234: TS_BEuler *beuler = (TS_BEuler*)ts->data;
235: int ierr,M,m;
236: Scalar mdt = 1.0/ts->time_step,mone = -1.0;
239: SLESSetFromOptions(ts->sles);
240: VecDuplicate(ts->vec_sol,&beuler->update);
241: VecDuplicate(ts->vec_sol,&beuler->rhs);
242:
243: /* build linear system to be solved */
244: if (!ts->Ashell) {
245: MatScale(&mone,ts->A);
246: MatShift(&mdt,ts->A);
247: } else {
248: /* construct new shell matrix */
249: VecGetSize(ts->vec_sol,&M);
250: VecGetLocalSize(ts->vec_sol,&m);
251: MatCreateShell(ts->comm,m,M,M,M,ts,&ts->A);
252: MatShellSetOperation(ts->A,MATOP_MULT,(void(*)())TSBEulerMatMult);
253: }
254: if (ts->A != ts->B && ts->Ashell != ts->B) {
255: MatScale(&mone,ts->B);
256: MatShift(&mdt,ts->B);
257: }
258: SLESSetOperators(ts->sles,ts->A,ts->B,SAME_NONZERO_PATTERN);
259: return(0);
260: }
262: static int TSSetUp_BEuler_Linear_Variable_Matrix(TS ts)
263: {
264: TS_BEuler *beuler = (TS_BEuler*)ts->data;
265: int ierr,M,m;
268: SLESSetFromOptions(ts->sles);
269: VecDuplicate(ts->vec_sol,&beuler->update);
270: VecDuplicate(ts->vec_sol,&beuler->rhs);
271: if (ts->Ashell) { /* construct new shell matrix */
272: VecGetSize(ts->vec_sol,&M);
273: VecGetLocalSize(ts->vec_sol,&m);
274: MatCreateShell(ts->comm,m,M,M,M,ts,&ts->A);
275: MatShellSetOperation(ts->A,MATOP_MULT,(void(*)())TSBEulerMatMult);
276: }
277: return(0);
278: }
280: static int TSSetUp_BEuler_Nonlinear(TS ts)
281: {
282: TS_BEuler *beuler = (TS_BEuler*)ts->data;
283: int ierr,M,m;
286: SNESSetFromOptions(ts->snes);
287: VecDuplicate(ts->vec_sol,&beuler->update);
288: VecDuplicate(ts->vec_sol,&beuler->func);
289: SNESSetFunction(ts->snes,beuler->func,TSBEulerFunction,ts);
290: if (ts->Ashell) { /* construct new shell matrix */
291: VecGetSize(ts->vec_sol,&M);
292: VecGetLocalSize(ts->vec_sol,&m);
293: MatCreateShell(ts->comm,m,M,M,M,ts,&ts->A);
294: MatShellSetOperation(ts->A,MATOP_MULT,(void(*)())TSBEulerMatMult);
295: }
296: SNESSetJacobian(ts->snes,ts->A,ts->B,TSBEulerJacobian,ts);
297: return(0);
298: }
299: /*------------------------------------------------------------*/
301: static int TSSetFromOptions_BEuler_Linear(TS ts)
302: {
304:
305: return(0);
306: }
308: static int TSSetFromOptions_BEuler_Nonlinear(TS ts)
309: {
311:
312: return(0);
313: }
315: static int TSView_BEuler(TS ts,PetscViewer viewer)
316: {
318: return(0);
319: }
321: /* ------------------------------------------------------------ */
322: EXTERN_C_BEGIN
323: int TSCreate_BEuler(TS ts)
324: {
325: TS_BEuler *beuler;
326: int ierr;
327: KSP ksp;
328: PetscTruth isshell;
331: ts->destroy = TSDestroy_BEuler;
332: ts->view = TSView_BEuler;
334: if (ts->problem_type == TS_LINEAR) {
335: if (!ts->A) {
336: SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set rhs matrix for linear problem");
337: }
338: PetscTypeCompare((PetscObject)ts->A,MATSHELL,&isshell);
339: if (!ts->rhsmatrix) {
340: if (isshell) {
341: ts->Ashell = ts->A;
342: }
343: ts->setup = TSSetUp_BEuler_Linear_Constant_Matrix;
344: ts->step = TSStep_BEuler_Linear_Constant_Matrix;
345: } else {
346: if (isshell) {
347: ts->Ashell = ts->A;
348: }
349: ts->setup = TSSetUp_BEuler_Linear_Variable_Matrix;
350: ts->step = TSStep_BEuler_Linear_Variable_Matrix;
351: }
352: ts->setfromoptions = TSSetFromOptions_BEuler_Linear;
353: SLESCreate(ts->comm,&ts->sles);
354: SLESGetKSP(ts->sles,&ksp);
355: KSPSetInitialGuessNonzero(ksp);
356: } else if (ts->problem_type == TS_NONLINEAR) {
357: PetscTypeCompare((PetscObject)ts->A,MATSHELL,&isshell);
358: if (isshell) {
359: ts->Ashell = ts->A;
360: }
361: ts->setup = TSSetUp_BEuler_Nonlinear;
362: ts->step = TSStep_BEuler_Nonlinear;
363: ts->setfromoptions = TSSetFromOptions_BEuler_Nonlinear;
364: SNESCreate(ts->comm,SNES_NONLINEAR_EQUATIONS,&ts->snes);
365: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"No such problem");
367: PetscNew(TS_BEuler,&beuler);
368: PetscLogObjectMemory(ts,sizeof(TS_BEuler));
369: ierr = PetscMemzero(beuler,sizeof(TS_BEuler));
370: ts->data = (void*)beuler;
372: return(0);
373: }
374: EXTERN_C_END