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: }