Actual source code: beuler.c
1: /*
2: Code for Timestepping with implicit backwards Euler.
3: */
4: #include src/ts/tsimpl.h
6: typedef struct {
7: Vec update; /* work vector where new solution is formed */
8: Vec func; /* work vector where F(t[i],u[i]) is stored */
9: Vec rhs; /* work vector for RHS; vec_sol/dt */
10: } TS_BEuler;
12: /*------------------------------------------------------------------------------*/
14: /*
15: Version for linear PDE where RHS does not depend on time. Has built a
16: single matrix that is to be used for all timesteps.
17: */
20: static PetscErrorCode TSStep_BEuler_Linear_Constant_Matrix(TS ts,PetscInt *steps,PetscReal *ptime)
21: {
22: TS_BEuler *beuler = (TS_BEuler*)ts->data;
23: Vec sol = ts->vec_sol,update = beuler->update;
24: Vec rhs = beuler->rhs;
26: PetscInt i,max_steps = ts->max_steps,its;
27: PetscScalar mdt = 1.0/ts->time_step;
28: KSP ksp;
31: TSGetKSP(ts,&ksp);
32: *steps = -ts->steps;
33: TSMonitor(ts,ts->steps,ts->ptime,sol);
35: /* set initial guess to be previous solution */
36: VecCopy(sol,update);
38: for (i=0; i<max_steps; i++) {
39: VecCopy(sol,rhs);
40: VecScale(&mdt,rhs);
41: /* apply user-provided boundary conditions (only needed if they are time dependent) */
42: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
44: ts->ptime += ts->time_step;
45: if (ts->ptime > ts->max_time) break;
46: KSPSolve(ts->ksp,rhs,update);
47: KSPGetIterationNumber(ksp,&its);
48: ts->linear_its += its;
49: VecCopy(update,sol);
50: ts->steps++;
51: TSMonitor(ts,ts->steps,ts->ptime,sol);
52: }
54: *steps += ts->steps;
55: *ptime = ts->ptime;
56: return(0);
57: }
59: /*
60: Version where matrix depends on time
61: */
64: static PetscErrorCode TSStep_BEuler_Linear_Variable_Matrix(TS ts,PetscInt *steps,PetscReal *ptime)
65: {
66: TS_BEuler *beuler = (TS_BEuler*)ts->data;
67: Vec sol = ts->vec_sol,update = beuler->update,rhs = beuler->rhs;
69: PetscInt i,max_steps = ts->max_steps,its;
70: PetscScalar mdt = 1.0/ts->time_step;
71: MatStructure str;
72: KSP ksp;
75: TSGetKSP(ts,&ksp);
76: *steps = -ts->steps;
77: TSMonitor(ts,ts->steps,ts->ptime,sol);
79: /* set initial guess to be previous solution */
80: VecCopy(sol,update);
82: for (i=0; i<max_steps; i++) {
83: VecCopy(sol,rhs);
84: VecScale(&mdt,rhs);
85: /* apply user-provided boundary conditions (only needed if they are time dependent) */
86: TSComputeRHSBoundaryConditions(ts,ts->ptime,rhs);
88: ts->ptime += ts->time_step;
89: if (ts->ptime > ts->max_time) break;
90: /*
91: evaluate matrix function
92: */
93: (*ts->ops->rhsmatrix)(ts,ts->ptime,&ts->A,&ts->B,&str,ts->jacP);
94: TSScaleShiftMatrices(ts,ts->A,ts->B,str);
95: KSPSetOperators(ts->ksp,ts->A,ts->B,str);
96: KSPSolve(ts->ksp,rhs,update);
97: KSPGetIterationNumber(ksp,&its);
98: ts->linear_its += its;
99: VecCopy(update,sol);
100: ts->steps++;
101: TSMonitor(ts,ts->steps,ts->ptime,sol);
102: }
104: *steps += ts->steps;
105: *ptime = ts->ptime;
106: return(0);
107: }
108: /*
109: Version for nonlinear PDE.
110: */
113: static PetscErrorCode TSStep_BEuler_Nonlinear(TS ts,PetscInt *steps,PetscReal *ptime)
114: {
115: Vec sol = ts->vec_sol;
117: PetscInt i,max_steps = ts->max_steps,its,lits;
118: TS_BEuler *beuler = (TS_BEuler*)ts->data;
119:
121: *steps = -ts->steps;
122: TSMonitor(ts,ts->steps,ts->ptime,sol);
124: for (i=0; i<max_steps; i++) {
125: ts->ptime += ts->time_step;
126: if (ts->ptime > ts->max_time) break;
127: VecCopy(sol,beuler->update);
128: SNESSolve(ts->snes,beuler->update);
129: SNESGetNumberLinearIterations(ts->snes,&lits);
130: SNESGetIterationNumber(ts->snes,&its);
131: ts->nonlinear_its += its; ts->linear_its += lits;
132: VecCopy(beuler->update,sol);
133: ts->steps++;
134: TSMonitor(ts,ts->steps,ts->ptime,sol);
135: }
137: *steps += ts->steps;
138: *ptime = ts->ptime;
139: return(0);
140: }
142: /*------------------------------------------------------------*/
145: static PetscErrorCode TSDestroy_BEuler(TS ts)
146: {
147: TS_BEuler *beuler = (TS_BEuler*)ts->data;
151: if (beuler->update) {VecDestroy(beuler->update);}
152: if (beuler->func) {VecDestroy(beuler->func);}
153: if (beuler->rhs) {VecDestroy(beuler->rhs);}
154: PetscFree(beuler);
155: return(0);
156: }
160: /*
161: This defines the nonlinear equation that is to be solved with SNES
163: U^{n+1} - dt*F(U^{n+1}) - U^{n}
164: */
167: PetscErrorCode TSBEulerFunction(SNES snes,Vec x,Vec y,void *ctx)
168: {
169: TS ts = (TS) ctx;
170: PetscScalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
172: PetscInt i,n;
175: /* apply user-provided function */
176: TSComputeRHSFunction(ts,ts->ptime,x,y);
177: /* (u^{n+1} - U^{n})/dt - F(u^{n+1}) */
178: VecGetArray(ts->vec_sol,&un);
179: VecGetArray(x,&unp1);
180: VecGetArray(y,&Funp1);
181: VecGetLocalSize(x,&n);
183: for (i=0; i<n; i++) {
184: Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
185: }
186: VecRestoreArray(ts->vec_sol,&un);
187: VecRestoreArray(x,&unp1);
188: VecRestoreArray(y,&Funp1);
189: return(0);
190: }
192: /*
193: This constructs the Jacobian needed for SNES
195: J = I/dt - J_{F} where J_{F} is the given Jacobian of F.
196: */
199: PetscErrorCode TSBEulerJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
200: {
201: TS ts = (TS) ctx;
205: /* construct user's Jacobian */
206: TSComputeRHSJacobian(ts,ts->ptime,x,AA,BB,str);
208: /* shift and scale Jacobian */
209: /* this test is a undesirable hack, we assume that if it is MATMFFD then it is
210: obtained from -snes_mf_operator and there is computed directly from the
211: FormFunction() SNES is given and therefor does not need to be shifted/scaled
212: BUT maybe it could be MATMFFD and does require shift in some other case? */
213: TSScaleShiftMatrices(ts,*AA,*BB,*str);
214: return(0);
215: }
217: /* ------------------------------------------------------------*/
220: static PetscErrorCode TSSetUp_BEuler_Linear_Constant_Matrix(TS ts)
221: {
222: TS_BEuler *beuler = (TS_BEuler*)ts->data;
226: KSPSetFromOptions(ts->ksp);
227: VecDuplicate(ts->vec_sol,&beuler->update);
228: VecDuplicate(ts->vec_sol,&beuler->rhs);
229:
230: /* build linear system to be solved */
231: TSScaleShiftMatrices(ts,ts->A,ts->B,SAME_NONZERO_PATTERN);
232: KSPSetOperators(ts->ksp,ts->A,ts->B,SAME_NONZERO_PATTERN);
233: return(0);
234: }
238: static PetscErrorCode TSSetUp_BEuler_Linear_Variable_Matrix(TS ts)
239: {
240: TS_BEuler *beuler = (TS_BEuler*)ts->data;
244: KSPSetFromOptions(ts->ksp);
245: VecDuplicate(ts->vec_sol,&beuler->update);
246: VecDuplicate(ts->vec_sol,&beuler->rhs);
247: return(0);
248: }
252: static PetscErrorCode TSSetUp_BEuler_Nonlinear(TS ts)
253: {
254: TS_BEuler *beuler = (TS_BEuler*)ts->data;
258: VecDuplicate(ts->vec_sol,&beuler->update);
259: VecDuplicate(ts->vec_sol,&beuler->func);
260: SNESSetFunction(ts->snes,beuler->func,TSBEulerFunction,ts);
261: SNESSetJacobian(ts->snes,ts->A,ts->B,TSBEulerJacobian,ts);
262: return(0);
263: }
264: /*------------------------------------------------------------*/
268: static PetscErrorCode TSSetFromOptions_BEuler_Linear(TS ts)
269: {
271: return(0);
272: }
276: static PetscErrorCode TSSetFromOptions_BEuler_Nonlinear(TS ts)
277: {
279: return(0);
280: }
284: static PetscErrorCode TSView_BEuler(TS ts,PetscViewer viewer)
285: {
287: return(0);
288: }
290: /* ------------------------------------------------------------ */
291: /*MC
292: TS_BEULER - ODE solver using the implicit backward Euler method
294: Level: beginner
296: .seealso: TSCreate(), TS, TSSetType(), TS_EULER
298: M*/
302: PetscErrorCode TSCreate_BEuler(TS ts)
303: {
304: TS_BEuler *beuler;
308: ts->ops->destroy = TSDestroy_BEuler;
309: ts->ops->view = TSView_BEuler;
311: if (ts->problem_type == TS_LINEAR) {
312: if (!ts->A) {
313: SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set rhs matrix for linear problem");
314: }
315: if (!ts->ops->rhsmatrix) {
316: ts->ops->setup = TSSetUp_BEuler_Linear_Constant_Matrix;
317: ts->ops->step = TSStep_BEuler_Linear_Constant_Matrix;
318: } else {
319: ts->ops->setup = TSSetUp_BEuler_Linear_Variable_Matrix;
320: ts->ops->step = TSStep_BEuler_Linear_Variable_Matrix;
321: }
322: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Linear;
323: KSPCreate(ts->comm,&ts->ksp);
324: KSPSetInitialGuessNonzero(ts->ksp,PETSC_TRUE);
325: } else if (ts->problem_type == TS_NONLINEAR) {
326: ts->ops->setup = TSSetUp_BEuler_Nonlinear;
327: ts->ops->step = TSStep_BEuler_Nonlinear;
328: ts->ops->setfromoptions = TSSetFromOptions_BEuler_Nonlinear;
329: SNESCreate(ts->comm,&ts->snes);
330: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"No such problem");
332: PetscNew(TS_BEuler,&beuler);
333: PetscLogObjectMemory(ts,sizeof(TS_BEuler));
334: PetscMemzero(beuler,sizeof(TS_BEuler));
335: ts->data = (void*)beuler;
337: return(0);
338: }