Actual source code: beuler.c
1: #define PETSCTS_DLL
3: /*
4: Code for Timestepping with implicit backwards Euler.
5: */
6: #include src/ts/tsimpl.h
8: typedef struct {
9: Vec update; /* work vector where new solution is formed */
10: Vec func; /* work vector where F(t[i],u[i]) is stored */
11: Vec rhs; /* work vector for RHS; vec_sol/dt */
12: } TS_BEuler;
14: /*------------------------------------------------------------------------------*/
16: /*
17: Version for linear PDE where RHS does not depend on time. Has built a
18: single matrix that is to be used for all timesteps.
19: */
22: static PetscErrorCode TSStep_BEuler_Linear_Constant_Matrix(TS ts,PetscInt *steps,PetscReal *ptime)
23: {
24: TS_BEuler *beuler = (TS_BEuler*)ts->data;
25: Vec sol = ts->vec_sol,update = beuler->update;
26: Vec rhs = beuler->rhs;
28: PetscInt i,max_steps = ts->max_steps,its;
29: PetscScalar mdt = 1.0/ts->time_step;
30: KSP ksp;
33: TSGetKSP(ts,&ksp);
34: *steps = -ts->steps;
35: TSMonitor(ts,ts->steps,ts->ptime,sol);
37: /* set initial guess to be previous solution */
38: VecCopy(sol,update);
40: for (i=0; i<max_steps; i++) {
41: VecCopy(sol,rhs);
42: VecScale(rhs,mdt);
43: /* apply user-provided boundary conditions (only needed if they are time dependent) */
44: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
46: ts->ptime += ts->time_step;
47: if (ts->ptime > ts->max_time) break;
48: KSPSolve(ts->ksp,rhs,update);
49: KSPGetIterationNumber(ksp,&its);
50: ts->linear_its += its;
51: VecCopy(update,sol);
52: ts->steps++;
53: TSMonitor(ts,ts->steps,ts->ptime,sol);
54: }
56: *steps += ts->steps;
57: *ptime = ts->ptime;
58: return(0);
59: }
61: /*
62: Version where matrix depends on time
63: */
66: static PetscErrorCode TSStep_BEuler_Linear_Variable_Matrix(TS ts,PetscInt *steps,PetscReal *ptime)
67: {
68: TS_BEuler *beuler = (TS_BEuler*)ts->data;
69: Vec sol = ts->vec_sol,update = beuler->update,rhs = beuler->rhs;
71: PetscInt i,max_steps = ts->max_steps,its;
72: PetscScalar mdt = 1.0/ts->time_step;
73: MatStructure str;
74: KSP ksp;
77: TSGetKSP(ts,&ksp);
78: *steps = -ts->steps;
79: TSMonitor(ts,ts->steps,ts->ptime,sol);
81: /* set initial guess to be previous solution */
82: VecCopy(sol,update);
84: for (i=0; i<max_steps; i++) {
85: VecCopy(sol,rhs);
86: VecScale(rhs,mdt);
87: /* apply user-provided boundary conditions (only needed if they are time dependent) */
88: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
90: ts->ptime += ts->time_step;
91: if (ts->ptime > ts->max_time) break;
92: /*
93: evaluate matrix function
94: */
95: (*ts->ops->rhsmatrix)(ts,ts->ptime,&ts->A,&ts->B,&str,ts->jacP);
96: TSScaleShiftMatrices(ts,ts->A,ts->B,str);
97: KSPSetOperators(ts->ksp,ts->A,ts->B,str);
98: KSPSolve(ts->ksp,rhs,update);
99: KSPGetIterationNumber(ksp,&its);
100: ts->linear_its += its;
101: VecCopy(update,sol);
102: ts->steps++;
103: TSMonitor(ts,ts->steps,ts->ptime,sol);
104: }
106: *steps += ts->steps;
107: *ptime = ts->ptime;
108: return(0);
109: }
110: /*
111: Version for nonlinear PDE.
112: */
115: static PetscErrorCode TSStep_BEuler_Nonlinear(TS ts,PetscInt *steps,PetscReal *ptime)
116: {
117: Vec sol = ts->vec_sol;
119: PetscInt i,max_steps = ts->max_steps,its,lits;
120: TS_BEuler *beuler = (TS_BEuler*)ts->data;
121:
123: *steps = -ts->steps;
124: TSMonitor(ts,ts->steps,ts->ptime,sol);
126: for (i=0; i<max_steps; i++) {
127: ts->ptime += ts->time_step;
128: if (ts->ptime > ts->max_time) break;
129: VecCopy(sol,beuler->update);
130: SNESSolve(ts->snes,PETSC_NULL,beuler->update);
131: SNESGetNumberLinearIterations(ts->snes,&lits);
132: SNESGetIterationNumber(ts->snes,&its);
133: ts->nonlinear_its += its; ts->linear_its += lits;
134: VecCopy(beuler->update,sol);
135: ts->steps++;
136: TSMonitor(ts,ts->steps,ts->ptime,sol);
137: }
139: *steps += ts->steps;
140: *ptime = ts->ptime;
141: return(0);
142: }
144: /*------------------------------------------------------------*/
147: static PetscErrorCode TSDestroy_BEuler(TS ts)
148: {
149: TS_BEuler *beuler = (TS_BEuler*)ts->data;
153: if (beuler->update) {VecDestroy(beuler->update);}
154: if (beuler->func) {VecDestroy(beuler->func);}
155: if (beuler->rhs) {VecDestroy(beuler->rhs);}
156: PetscFree(beuler);
157: return(0);
158: }
162: /*
163: This defines the nonlinear equation that is to be solved with SNES
165: U^{n+1} - dt*F(U^{n+1}) - U^{n}
166: */
169: PetscErrorCode TSBEulerFunction(SNES snes,Vec x,Vec y,void *ctx)
170: {
171: TS ts = (TS) ctx;
172: PetscScalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
174: PetscInt i,n;
177: /* apply user-provided function */
178: TSComputeRHSFunction(ts,ts->ptime,x,y);
179: /* (u^{n+1} - U^{n})/dt - F(u^{n+1}) */
180: VecGetArray(ts->vec_sol,&un);
181: VecGetArray(x,&unp1);
182: VecGetArray(y,&Funp1);
183: VecGetLocalSize(x,&n);
185: for (i=0; i<n; i++) {
186: Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
187: }
188: VecRestoreArray(ts->vec_sol,&un);
189: VecRestoreArray(x,&unp1);
190: VecRestoreArray(y,&Funp1);
191: return(0);
192: }
194: /*
195: This constructs the Jacobian needed for SNES
197: J = I/dt - J_{F} where J_{F} is the given Jacobian of F.
198: */
201: PetscErrorCode TSBEulerJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
202: {
203: TS ts = (TS) ctx;
207: /* construct user's Jacobian */
208: TSComputeRHSJacobian(ts,ts->ptime,x,AA,BB,str);
210: /* shift and scale Jacobian */
211: /* this test is a undesirable hack, we assume that if it is MATMFFD then it is
212: obtained from -snes_mf_operator and there is computed directly from the
213: FormFunction() SNES is given and therefor does not need to be shifted/scaled
214: BUT maybe it could be MATMFFD and does require shift in some other case? */
215: TSScaleShiftMatrices(ts,*AA,*BB,*str);
216: return(0);
217: }
219: /* ------------------------------------------------------------*/
222: static PetscErrorCode TSSetUp_BEuler_Linear_Constant_Matrix(TS ts)
223: {
224: TS_BEuler *beuler = (TS_BEuler*)ts->data;
228: KSPSetFromOptions(ts->ksp);
229: VecDuplicate(ts->vec_sol,&beuler->update);
230: VecDuplicate(ts->vec_sol,&beuler->rhs);
231:
232: /* build linear system to be solved */
233: TSScaleShiftMatrices(ts,ts->A,ts->B,SAME_NONZERO_PATTERN);
234: KSPSetOperators(ts->ksp,ts->A,ts->B,SAME_NONZERO_PATTERN);
235: return(0);
236: }
240: static PetscErrorCode TSSetUp_BEuler_Linear_Variable_Matrix(TS ts)
241: {
242: TS_BEuler *beuler = (TS_BEuler*)ts->data;
246: KSPSetFromOptions(ts->ksp);
247: VecDuplicate(ts->vec_sol,&beuler->update);
248: VecDuplicate(ts->vec_sol,&beuler->rhs);
249: return(0);
250: }
254: static PetscErrorCode TSSetUp_BEuler_Nonlinear(TS ts)
255: {
256: TS_BEuler *beuler = (TS_BEuler*)ts->data;
260: VecDuplicate(ts->vec_sol,&beuler->update);
261: VecDuplicate(ts->vec_sol,&beuler->func);
262: SNESSetFunction(ts->snes,beuler->func,TSBEulerFunction,ts);
263: SNESSetJacobian(ts->snes,ts->A,ts->B,TSBEulerJacobian,ts);
264: return(0);
265: }
266: /*------------------------------------------------------------*/
270: static PetscErrorCode TSSetFromOptions_BEuler_Linear(TS ts)
271: {
273: return(0);
274: }
278: static PetscErrorCode TSSetFromOptions_BEuler_Nonlinear(TS ts)
279: {
281: return(0);
282: }
286: static PetscErrorCode TSView_BEuler(TS ts,PetscViewer viewer)
287: {
289: return(0);
290: }
292: /* ------------------------------------------------------------ */
293: /*MC
294: TS_BEULER - ODE solver using the implicit backward Euler method
296: Level: beginner
298: .seealso: TSCreate(), TS, TSSetType(), TS_EULER
300: M*/
304: PetscErrorCode PETSCTS_DLLEXPORT TSCreate_BEuler(TS ts)
305: {
306: TS_BEuler *beuler;
310: ts->ops->destroy = TSDestroy_BEuler;
311: ts->ops->view = TSView_BEuler;
313: if (ts->problem_type == TS_LINEAR) {
314: if (!ts->A) {
315: SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set rhs matrix for linear problem");
316: }
317: if (!ts->ops->rhsmatrix) {
318: ts->ops->setup = TSSetUp_BEuler_Linear_Constant_Matrix;
319: ts->ops->step = TSStep_BEuler_Linear_Constant_Matrix;
320: } else {
321: ts->ops->setup = TSSetUp_BEuler_Linear_Variable_Matrix;
322: ts->ops->step = TSStep_BEuler_Linear_Variable_Matrix;
323: }
324: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Linear;
325: KSPCreate(ts->comm,&ts->ksp);
326: KSPSetInitialGuessNonzero(ts->ksp,PETSC_TRUE);
327: } else if (ts->problem_type == TS_NONLINEAR) {
328: ts->ops->setup = TSSetUp_BEuler_Nonlinear;
329: ts->ops->step = TSStep_BEuler_Nonlinear;
330: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Nonlinear;
331: SNESCreate(ts->comm,&ts->snes);
332: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"No such problem");
334: PetscNew(TS_BEuler,&beuler);
335: PetscLogObjectMemory(ts,sizeof(TS_BEuler));
336: ts->data = (void*)beuler;
338: return(0);
339: }