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