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