Actual source code: posindep.c

  1: /*$Id: posindep.c,v 1.55 2001/04/04 18:04:13 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 */

 12:   /* information used for Pseudo-timestepping */

 14:   int    (*dt)(TS,double*,void*);              /* compute next timestep, and related context */
 15:   void   *dtctx;
 16:   int    (*verify)(TS,Vec,void*,double*,int*); /* verify previous timestep and related context */
 17:   void   *verifyctx;

 19:   double initial_fnorm,fnorm;                  /* original and current norm of F(u) */
 20:   double fnorm_previous;

 22:   double     dt_increment;                  /* scaling that dt is incremented each time-step */
 23:   PetscTruth increment_dt_from_initial_dt;
 24: } TS_Pseudo;

 26: /* ------------------------------------------------------------------------------*/

 28: /*@
 29:     TSPseudoComputeTimeStep - Computes the next timestep for a currently running
 30:     pseudo-timestepping process.

 32:     Collective on TS

 34:     Input Parameter:
 35: .   ts - timestep context

 37:     Output Parameter:
 38: .   dt - newly computed timestep

 40:     Level: advanced

 42:     Notes:
 43:     The routine to be called here to compute the timestep should be
 44:     set by calling TSPseudoSetTimeStep().

 46: .keywords: timestep, pseudo, compute

 48: .seealso: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep()
 49: @*/
 50: int TSPseudoComputeTimeStep(TS ts,double *dt)
 51: {
 52:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
 53:   int       ierr;

 56:   PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);
 57:   (*pseudo->dt)(ts,dt,pseudo->dtctx);
 58:   PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);
 59:   return(0);
 60: }


 63: /* ------------------------------------------------------------------------------*/
 64: /*@C
 65:    TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep.

 67:    Collective on TS

 69:    Input Parameters:
 70: +  ts - the timestep context
 71: .  dtctx - unused timestep context
 72: -  update - latest solution vector

 74:    Output Parameters:
 75: +  newdt - the timestep to use for the next step
 76: -  flag - flag indicating whether the last time step was acceptable

 78:    Level: advanced

 80:    Note:
 81:    This routine always returns a flag of 1, indicating an acceptable 
 82:    timestep.

 84: .keywords: timestep, pseudo, default, verify 

 86: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
 87: @*/
 88: int TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,double *newdt,int *flag)
 89: {
 91:   *flag = 1;
 92:   return(0);
 93: }


 96: /*@
 97:     TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.

 99:     Collective on TS

101:     Input Parameters:
102: +   ts - timestep context
103: -   update - latest solution vector

105:     Output Parameters:
106: +   dt - newly computed timestep (if it had to shrink)
107: -   flag - indicates if current timestep was ok

109:     Level: advanced

111:     Notes:
112:     The routine to be called here to compute the timestep should be
113:     set by calling TSPseudoSetVerifyTimeStep().

115: .keywords: timestep, pseudo, verify 

117: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep()
118: @*/
119: int TSPseudoVerifyTimeStep(TS ts,Vec update,double *dt,int *flag)
120: {
121:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
122:   int       ierr;

125:   if (!pseudo->verify) {*flag = 1; return(0);}

127:   (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);

129:   return(0);
130: }

132: /* --------------------------------------------------------------------------------*/

134: static int TSStep_Pseudo(TS ts,int *steps,double *ptime)
135: {
136:   Vec       sol = ts->vec_sol;
137:   int       ierr,i,max_steps = ts->max_steps,its,ok,lits;
138:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
139:   double    current_time_step;
140: 
142:   *steps = -ts->steps;

144:   VecCopy(sol,pseudo->update);
145:   for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) {
146:     TSPseudoComputeTimeStep(ts,&ts->time_step);
147:     current_time_step = ts->time_step;
148:     while (1) {
149:       ts->ptime  += current_time_step;
150:       SNESSolve(ts->snes,pseudo->update,&its);
151:       SNESGetNumberLinearIterations(ts->snes,&lits);
152:       ts->nonlinear_its += PetscAbsInt(its); ts->linear_its += lits;
153:       TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);
154:       if (ok) break;
155:       ts->ptime        -= current_time_step;
156:       current_time_step = ts->time_step;
157:     }
158:     VecCopy(pseudo->update,sol);
159:     ts->steps++;
160:     TSMonitor(ts,ts->steps,ts->ptime,sol);
161:   }

163:   *steps += ts->steps;
164:   *ptime  = ts->ptime;
165:   return(0);
166: }

168: /*------------------------------------------------------------*/
169: static int TSDestroy_Pseudo(TS ts)
170: {
171:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
172:   int       ierr;

175:   if (pseudo->update) {VecDestroy(pseudo->update);}
176:   if (pseudo->func) {VecDestroy(pseudo->func);}
177:   if (pseudo->rhs)  {VecDestroy(pseudo->rhs);}
178:   if (ts->Ashell)   {MatDestroy(ts->A);}
179:   PetscFree(pseudo);
180:   return(0);
181: }


184: /*------------------------------------------------------------*/
185: /*
186:     This matrix shell multiply where user provided Shell matrix
187: */

189: int TSPseudoMatMult(Mat mat,Vec x,Vec y)
190: {
191:   TS     ts;
192:   Scalar mdt,mone = -1.0;
193:   int    ierr;

196:   MatShellGetContext(mat,(void **)&ts);
197:   mdt = 1.0/ts->time_step;

199:   /* apply user provided function */
200:   MatMult(ts->Ashell,x,y);
201:   /* shift and scale by 1/dt - F */
202:   VecAXPBY(&mdt,&mone,x,y);
203:   return(0);
204: }

206: /* 
207:     This defines the nonlinear equation that is to be solved with SNES

209:               (U^{n+1} - U^{n})/dt - F(U^{n+1})
210: */
211: int TSPseudoFunction(SNES snes,Vec x,Vec y,void *ctx)
212: {
213:   TS     ts = (TS) ctx;
214:   Scalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
215:   int    ierr,i,n;

218:   /* apply user provided function */
219:   TSComputeRHSFunction(ts,ts->ptime,x,y);
220:   /* compute (u^{n+1) - u^{n})/dt - F(u^{n+1}) */
221:   VecGetArray(ts->vec_sol,&un);
222:   VecGetArray(x,&unp1);
223:   VecGetArray(y,&Funp1);
224:   VecGetLocalSize(x,&n);
225:   for (i=0; i<n; i++) {
226:     Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
227:   }
228:   VecRestoreArray(ts->vec_sol,&un);
229:   VecRestoreArray(x,&unp1);
230:   VecRestoreArray(y,&Funp1);

232:   return(0);
233: }

235: /*
236:    This constructs the Jacobian needed for SNES 

238:              J = I/dt - J_{F}   where J_{F} is the given Jacobian of F.
239: */
240: int TSPseudoJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
241: {
242:   TS         ts = (TS) ctx;
243:   int        ierr;
244:   Scalar     mone = -1.0,mdt = 1.0/ts->time_step;
245:   PetscTruth isshell;

248:   /* construct users Jacobian */
249:   TSComputeRHSJacobian(ts,ts->ptime,x,AA,BB,str);

251:   /* shift and scale Jacobian, if not a shell matrix */
252:   PetscTypeCompare((PetscObject)*AA,MATSHELL,&isshell);
253:   if (!isshell) {
254:     MatScale(&mone,*AA);
255:     MatShift(&mdt,*AA);
256:   }
257:   PetscTypeCompare((PetscObject)*BB,MATSHELL,&isshell);
258:   if (*BB != *AA && *str != SAME_PRECONDITIONER && !isshell) {
259:     MatScale(&mone,*BB);
260:     MatShift(&mdt,*BB);
261:   }

263:   return(0);
264: }


267: static int TSSetUp_Pseudo(TS ts)
268: {
269:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
270:   int       ierr,M,m;

273:   SNESSetFromOptions(ts->snes);
274:   VecDuplicate(ts->vec_sol,&pseudo->update);
275:   VecDuplicate(ts->vec_sol,&pseudo->func);
276:   SNESSetFunction(ts->snes,pseudo->func,TSPseudoFunction,ts);
277:   if (ts->Ashell) { /* construct new shell matrix */
278:     VecGetSize(ts->vec_sol,&M);
279:     VecGetLocalSize(ts->vec_sol,&m);
280:     MatCreateShell(ts->comm,m,M,M,M,ts,&ts->A);
281:     MatShellSetOperation(ts->A,MATOP_MULT,(void(*)())TSPseudoMatMult);
282:   }
283:   SNESSetJacobian(ts->snes,ts->A,ts->B,TSPseudoJacobian,ts);
284:   return(0);
285: }
286: /*------------------------------------------------------------*/

288: int TSPseudoDefaultMonitor(TS ts,int step,double ptime,Vec v,void *ctx)
289: {
290:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
291:   int       ierr;

294:   (*PetscHelpPrintf)(ts->comm,"TS %d dt %g time %g fnorm %gn",step,ts->time_step,ptime,pseudo->fnorm);
295:   return(0);
296: }

298: static int TSSetFromOptions_Pseudo(TS ts)
299: {
300:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
301:   int        ierr;
302:   PetscTruth flg;


306:   PetscOptionsHead("Pseudo-timestepping options");
307:     PetscOptionsName("-ts_monitor","Monitor convergence","TSPseudoDefaultMonitor",&flg);
308:     if (flg) {
309:       TSSetMonitor(ts,TSPseudoDefaultMonitor,PETSC_NULL,PETSC_NULL);
310:     }
311:     PetscOptionsName("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",&flg);
312:     if (flg) {
313:       TSPseudoIncrementDtFromInitialDt(ts);
314:     }
315:     PetscOptionsDouble("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);
316:   PetscOptionsTail();

318:   return(0);
319: }

321: static int TSView_Pseudo(TS ts,PetscViewer viewer)
322: {
324:   return(0);
325: }

327: /* ----------------------------------------------------------------------------- */
328: /*@
329:    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 
330:    last timestep.

332:    Collective on TS

334:    Input Parameters:
335: +  ts - timestep context
336: .  dt - user-defined function to verify timestep
337: -  ctx - [optional] user-defined context for private data
338:          for the timestep verification routine (may be PETSC_NULL)

340:    Level: advanced

342:    Calling sequence of func:
343: .  func (TS ts,Vec update,void *ctx,double *newdt,int *flag);

345: .  update - latest solution vector
346: .  ctx - [optional] timestep context
347: .  newdt - the timestep to use for the next step
348: .  flag - flag indicating whether the last time step was acceptable

350:    Notes:
351:    The routine set here will be called by TSPseudoVerifyTimeStep()
352:    during the timestepping process.

354: .keywords: timestep, pseudo, set, verify 

356: .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
357: @*/
358: int TSPseudoSetVerifyTimeStep(TS ts,int (*dt)(TS,Vec,void*,double*,int*),void* ctx)
359: {
360:   int ierr,(*f)(TS,int (*)(TS,Vec,void*,double *,int *),void *);


365:   PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)())&f);
366:   if (f) {
367:     (*f)(ts,dt,ctx);
368:   }
369:   return(0);
370: }

372: /*@
373:     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to 
374:     dt when using the TSPseudoDefaultTimeStep() routine.

376:    Collective on TS

378:     Input Parameters:
379: +   ts - the timestep context
380: -   inc - the scaling factor >= 1.0

382:     Options Database Key:
383: $    -ts_pseudo_increment <increment>

385:     Level: advanced

387: .keywords: timestep, pseudo, set, increment

389: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
390: @*/
391: int TSPseudoSetTimeStepIncrement(TS ts,double inc)
392: {
393:   int ierr,(*f)(TS,double);


398:   PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)())&f);
399:   if (f) {
400:     (*f)(ts,inc);
401:   }
402:   return(0);
403: }

405: /*@
406:     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
407:     is computed via the formula
408: $         dt = initial_dt*initial_fnorm/current_fnorm 
409:       rather than the default update,
410: $         dt = current_dt*previous_fnorm/current_fnorm.

412:    Collective on TS

414:     Input Parameter:
415: .   ts - the timestep context

417:     Options Database Key:
418: $    -ts_pseudo_increment_dt_from_initial_dt

420:     Level: advanced

422: .keywords: timestep, pseudo, set, increment

424: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
425: @*/
426: int TSPseudoIncrementDtFromInitialDt(TS ts)
427: {
428:   int ierr,(*f)(TS);


433:   PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)())&f);
434:   if (f) {
435:     (*f)(ts);
436:   }
437:   return(0);
438: }


441: /*@
442:    TSPseudoSetTimeStep - Sets the user-defined routine to be
443:    called at each pseudo-timestep to update the timestep.

445:    Collective on TS

447:    Input Parameters:
448: +  ts - timestep context
449: .  dt - function to compute timestep
450: -  ctx - [optional] user-defined context for private data
451:          required by the function (may be PETSC_NULL)

453:    Level: intermediate

455:    Calling sequence of func:
456: .  func (TS ts,double *newdt,void *ctx);

458: .  newdt - the newly computed timestep
459: .  ctx - [optional] timestep context

461:    Notes:
462:    The routine set here will be called by TSPseudoComputeTimeStep()
463:    during the timestepping process.

465: .keywords: timestep, pseudo, set

467: .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
468: @*/
469: int TSPseudoSetTimeStep(TS ts,int (*dt)(TS,double*,void*),void* ctx)
470: {
471:   int ierr,(*f)(TS,int (*)(TS,double *,void *),void *);


476:   PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)())&f);
477:   if (f) {
478:     (*f)(ts,dt,ctx);
479:   }
480:   return(0);
481: }

483: /* ----------------------------------------------------------------------------- */

485: EXTERN_C_BEGIN
486: int TSPseudoSetVerifyTimeStep_Pseudo(TS ts,int (*dt)(TS,Vec,void*,double*,int*),void* ctx)
487: {
488:   TS_Pseudo *pseudo;

491:   pseudo              = (TS_Pseudo*)ts->data;
492:   pseudo->verify      = dt;
493:   pseudo->verifyctx   = ctx;
494:   return(0);
495: }
496: EXTERN_C_END

498: EXTERN_C_BEGIN
499: int TSPseudoSetTimeStepIncrement_Pseudo(TS ts,double inc)
500: {
501:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

504:   pseudo->dt_increment = inc;
505:   return(0);
506: }
507: EXTERN_C_END

509: EXTERN_C_BEGIN
510: int TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
511: {
512:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

515:   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
516:   return(0);
517: }
518: EXTERN_C_END

520: EXTERN_C_BEGIN
521: int TSPseudoSetTimeStep_Pseudo(TS ts,int (*dt)(TS,double*,void*),void* ctx)
522: {
523:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

526:   pseudo->dt      = dt;
527:   pseudo->dtctx   = ctx;
528:   return(0);
529: }
530: EXTERN_C_END

532: /* ----------------------------------------------------------------------------- */

534: EXTERN_C_BEGIN
535: int TSCreate_Pseudo(TS ts)
536: {
537:   TS_Pseudo  *pseudo;
538:   int        ierr;
539:   PetscTruth isshell;

542:   ts->destroy         = TSDestroy_Pseudo;
543:   ts->view            = TSView_Pseudo;

545:   if (ts->problem_type == TS_LINEAR) {
546:     SETERRQ(PETSC_ERR_ARG_WRONG,"Only for nonlinear problems");
547:   }
548:   if (!ts->A) {
549:     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set Jacobian");
550:   }

552:   PetscTypeCompare((PetscObject)ts->A,MATSHELL,&isshell);
553:   if (isshell) {
554:     ts->Ashell = ts->A;
555:   }
556:   ts->setup           = TSSetUp_Pseudo;
557:   ts->step            = TSStep_Pseudo;
558:   ts->setfromoptions  = TSSetFromOptions_Pseudo;

560:   /* create the required nonlinear solver context */
561:   SNESCreate(ts->comm,SNES_NONLINEAR_EQUATIONS,&ts->snes);

563:   PetscNew(TS_Pseudo,&pseudo);
564:   PetscLogObjectMemory(ts,sizeof(TS_Pseudo));

566:   ierr     = PetscMemzero(pseudo,sizeof(TS_Pseudo));
567:   ts->data = (void*)pseudo;

569:   pseudo->dt_increment                 = 1.1;
570:   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
571:   pseudo->dt                           = TSPseudoDefaultTimeStep;

573:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
574:                     "TSPseudoSetVerifyTimeStep_Pseudo",
575:                      TSPseudoSetVerifyTimeStep_Pseudo);
576:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
577:                     "TSPseudoSetTimeStepIncrement_Pseudo",
578:                      TSPseudoSetTimeStepIncrement_Pseudo);
579:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
580:                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
581:                      TSPseudoIncrementDtFromInitialDt_Pseudo);
582:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
583:                     "TSPseudoSetTimeStep_Pseudo",
584:                      TSPseudoSetTimeStep_Pseudo);
585:   return(0);
586: }
587: EXTERN_C_END

589: /*@C
590:    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
591:    Use with TSPseudoSetTimeStep().

593:    Collective on TS

595:    Input Parameters:
596: .  ts - the timestep context
597: .  dtctx - unused timestep context

599:    Output Parameter:
600: .  newdt - the timestep to use for the next step

602:    Level: advanced

604: .keywords: timestep, pseudo, default

606: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
607: @*/
608: int TSPseudoDefaultTimeStep(TS ts,double* newdt,void* dtctx)
609: {
610:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
611:   double    inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
612:   int       ierr;

615:   TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
616:   VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
617:   if (pseudo->initial_fnorm == 0.0) {
618:     /* first time through so compute initial function norm */
619:     pseudo->initial_fnorm = pseudo->fnorm;
620:     fnorm_previous        = pseudo->fnorm;
621:   }
622:   if (pseudo->fnorm == 0.0) {
623:     *newdt = 1.e12*inc*ts->time_step;
624:   } else if (pseudo->increment_dt_from_initial_dt) {
625:     *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm;
626:   } else {
627:     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
628:   }
629:   pseudo->fnorm_previous = pseudo->fnorm;
630:   return(0);
631: }