Actual source code: posindep.c

  1: /*$Id: posindep.c,v 1.60 2001/09/11 16:34:22 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 */

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

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

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

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

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

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

 34:     Collective on TS

 36:     Input Parameter:
 37: .   ts - timestep context

 39:     Output Parameter:
 40: .   dt - newly computed timestep

 42:     Level: advanced

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

 48: .keywords: timestep, pseudo, compute

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

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


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

 71:    Collective on TS

 73:    Input Parameters:
 74: +  ts - the timestep context
 75: .  dtctx - unused timestep context
 76: -  update - latest solution vector

 78:    Output Parameters:
 79: +  newdt - the timestep to use for the next step
 80: -  flag - flag indicating whether the last time step was acceptable

 82:    Level: advanced

 84:    Note:
 85:    This routine always returns a flag of 1, indicating an acceptable 
 86:    timestep.

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

 90: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
 91: @*/
 92: int TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,int *flag)
 93: {
 95:   *flag = 1;
 96:   return(0);
 97: }


102: /*@
103:     TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.

105:     Collective on TS

107:     Input Parameters:
108: +   ts - timestep context
109: -   update - latest solution vector

111:     Output Parameters:
112: +   dt - newly computed timestep (if it had to shrink)
113: -   flag - indicates if current timestep was ok

115:     Level: advanced

117:     Notes:
118:     The routine to be called here to compute the timestep should be
119:     set by calling TSPseudoSetVerifyTimeStep().

121: .keywords: timestep, pseudo, verify 

123: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep()
124: @*/
125: int TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,int *flag)
126: {
127:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
128:   int       ierr;

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

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

135:   return(0);
136: }

138: /* --------------------------------------------------------------------------------*/

142: static int TSStep_Pseudo(TS ts,int *steps,PetscReal *ptime)
143: {
144:   Vec       sol = ts->vec_sol;
145:   int       ierr,i,max_steps = ts->max_steps,its,ok,lits;
146:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
147:   PetscReal current_time_step;
148: 
150:   *steps = -ts->steps;

152:   VecCopy(sol,pseudo->update);
153:   for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) {
154:     TSPseudoComputeTimeStep(ts,&ts->time_step);
155:     TSMonitor(ts,ts->steps,ts->ptime,sol);
156:     current_time_step = ts->time_step;
157:     while (PETSC_TRUE) {
158:       ts->ptime  += current_time_step;
159:       SNESSolve(ts->snes,pseudo->update);
160:       SNESGetNumberLinearIterations(ts->snes,&lits);
161:       SNESGetIterationNumber(ts->snes,&its);
162:       ts->nonlinear_its += its; ts->linear_its += lits;
163:       TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);
164:       if (ok) break;
165:       ts->ptime        -= current_time_step;
166:       current_time_step = ts->time_step;
167:     }
168:     VecCopy(pseudo->update,sol);
169:     ts->steps++;
170:   }
171:   TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
172:   VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
173:   TSMonitor(ts,ts->steps,ts->ptime,sol);

175:   *steps += ts->steps;
176:   *ptime  = ts->ptime;
177:   return(0);
178: }

180: /*------------------------------------------------------------*/
183: static int TSDestroy_Pseudo(TS ts)
184: {
185:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
186:   int       ierr;

189:   if (pseudo->update) {VecDestroy(pseudo->update);}
190:   if (pseudo->func) {VecDestroy(pseudo->func);}
191:   if (pseudo->rhs)  {VecDestroy(pseudo->rhs);}
192:   PetscFree(pseudo);
193:   return(0);
194: }


197: /*------------------------------------------------------------*/

199: /* 
200:     This defines the nonlinear equation that is to be solved with SNES

202:               (U^{n+1} - U^{n})/dt - F(U^{n+1})
203: */
206: int TSPseudoFunction(SNES snes,Vec x,Vec y,void *ctx)
207: {
208:   TS     ts = (TS) ctx;
209:   PetscScalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
210:   int    ierr,i,n;

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

227:   return(0);
228: }

230: /*
231:    This constructs the Jacobian needed for SNES 

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

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

247:   /* shift and scale Jacobian */
248:   MatScale(&mone,*AA);
249:   MatShift(&mdt,*AA);
250:   if (*BB != *AA && *str != SAME_PRECONDITIONER) {
251:     MatScale(&mone,*BB);
252:     MatShift(&mdt,*BB);
253:   }

255:   return(0);
256: }


261: static int TSSetUp_Pseudo(TS ts)
262: {
263:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
264:   int       ierr;

267:   /* SNESSetFromOptions(ts->snes); */
268:   VecDuplicate(ts->vec_sol,&pseudo->update);
269:   VecDuplicate(ts->vec_sol,&pseudo->func);
270:   SNESSetFunction(ts->snes,pseudo->func,TSPseudoFunction,ts);
271:   SNESSetJacobian(ts->snes,ts->A,ts->B,TSPseudoJacobian,ts);
272:   return(0);
273: }
274: /*------------------------------------------------------------*/

278: int TSPseudoDefaultMonitor(TS ts,int step,PetscReal ptime,Vec v,void *ctx)
279: {
280:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
281:   int       ierr;

284:   (*PetscHelpPrintf)(ts->comm,"TS %d dt %g time %g fnorm %g\n",step,ts->time_step,ptime,pseudo->fnorm);
285:   return(0);
286: }

290: static int TSSetFromOptions_Pseudo(TS ts)
291: {
292:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
293:   int        ierr;
294:   PetscTruth flg;


298:   PetscOptionsHead("Pseudo-timestepping options");
299:     PetscOptionsName("-ts_monitor","Monitor convergence","TSPseudoDefaultMonitor",&flg);
300:     if (flg) {
301:       TSSetMonitor(ts,TSPseudoDefaultMonitor,PETSC_NULL,PETSC_NULL);
302:     }
303:     PetscOptionsName("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",&flg);
304:     if (flg) {
305:       TSPseudoIncrementDtFromInitialDt(ts);
306:     }
307:     PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);
308:   PetscOptionsTail();

310:   return(0);
311: }

315: static int TSView_Pseudo(TS ts,PetscViewer viewer)
316: {
318:   return(0);
319: }

321: /* ----------------------------------------------------------------------------- */
324: /*@C
325:    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 
326:    last timestep.

328:    Collective on TS

330:    Input Parameters:
331: +  ts - timestep context
332: .  dt - user-defined function to verify timestep
333: -  ctx - [optional] user-defined context for private data
334:          for the timestep verification routine (may be PETSC_NULL)

336:    Level: advanced

338:    Calling sequence of func:
339: .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,int *flag);

341: .  update - latest solution vector
342: .  ctx - [optional] timestep context
343: .  newdt - the timestep to use for the next step
344: .  flag - flag indicating whether the last time step was acceptable

346:    Notes:
347:    The routine set here will be called by TSPseudoVerifyTimeStep()
348:    during the timestepping process.

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

352: .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
353: @*/
354: int TSPseudoSetVerifyTimeStep(TS ts,int (*dt)(TS,Vec,void*,PetscReal*,int*),void* ctx)
355: {
356:   int ierr,(*f)(TS,int (*)(TS,Vec,void*,PetscReal *,int *),void *);


361:   PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);
362:   if (f) {
363:     (*f)(ts,dt,ctx);
364:   }
365:   return(0);
366: }

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

374:    Collective on TS

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

380:     Options Database Key:
381: $    -ts_pseudo_increment <increment>

383:     Level: advanced

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

387: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
388: @*/
389: int TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
390: {
391:   int ierr,(*f)(TS,PetscReal);


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

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 (**)(void))&f);
434:   if (f) {
435:     (*f)(ts);
436:   }
437:   return(0);
438: }


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

447:    Collective on TS

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

455:    Level: intermediate

457:    Calling sequence of func:
458: .  func (TS ts,PetscReal *newdt,void *ctx);

460: .  newdt - the newly computed timestep
461: .  ctx - [optional] timestep context

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

467: .keywords: timestep, pseudo, set

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


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

485: /* ----------------------------------------------------------------------------- */

487: typedef int (*FCN1)(TS,Vec,void*,PetscReal*,int*); /* force argument to next function to not be extern C*/
488: EXTERN_C_BEGIN
491: int TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
492: {
493:   TS_Pseudo *pseudo;

496:   pseudo              = (TS_Pseudo*)ts->data;
497:   pseudo->verify      = dt;
498:   pseudo->verifyctx   = ctx;
499:   return(0);
500: }
501: EXTERN_C_END

503: EXTERN_C_BEGIN
506: int TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
507: {
508:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

511:   pseudo->dt_increment = inc;
512:   return(0);
513: }
514: EXTERN_C_END

516: EXTERN_C_BEGIN
519: int TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
520: {
521:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

524:   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
525:   return(0);
526: }
527: EXTERN_C_END

529: typedef int (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
530: EXTERN_C_BEGIN
533: int TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
534: {
535:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

538:   pseudo->dt      = dt;
539:   pseudo->dtctx   = ctx;
540:   return(0);
541: }
542: EXTERN_C_END

544: /* ----------------------------------------------------------------------------- */

546: EXTERN_C_BEGIN
549: int TSCreate_Pseudo(TS ts)
550: {
551:   TS_Pseudo  *pseudo;
552:   int        ierr;

555:   ts->ops->destroy         = TSDestroy_Pseudo;
556:   ts->ops->view            = TSView_Pseudo;

558:   if (ts->problem_type == TS_LINEAR) {
559:     SETERRQ(PETSC_ERR_ARG_WRONG,"Only for nonlinear problems");
560:   }
561:   if (!ts->A) {
562:     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set Jacobian");
563:   }

565:   ts->ops->setup           = TSSetUp_Pseudo;
566:   ts->ops->step            = TSStep_Pseudo;
567:   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;

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

572:   PetscNew(TS_Pseudo,&pseudo);
573:   PetscLogObjectMemory(ts,sizeof(TS_Pseudo));

575:   PetscMemzero(pseudo,sizeof(TS_Pseudo));
576:   ts->data = (void*)pseudo;

578:   pseudo->dt_increment                 = 1.1;
579:   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
580:   pseudo->dt                           = TSPseudoDefaultTimeStep;

582:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
583:                     "TSPseudoSetVerifyTimeStep_Pseudo",
584:                      TSPseudoSetVerifyTimeStep_Pseudo);
585:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
586:                     "TSPseudoSetTimeStepIncrement_Pseudo",
587:                      TSPseudoSetTimeStepIncrement_Pseudo);
588:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
589:                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
590:                      TSPseudoIncrementDtFromInitialDt_Pseudo);
591:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
592:                     "TSPseudoSetTimeStep_Pseudo",
593:                      TSPseudoSetTimeStep_Pseudo);
594:   return(0);
595: }
596: EXTERN_C_END

600: /*@C
601:    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
602:    Use with TSPseudoSetTimeStep().

604:    Collective on TS

606:    Input Parameters:
607: .  ts - the timestep context
608: .  dtctx - unused timestep context

610:    Output Parameter:
611: .  newdt - the timestep to use for the next step

613:    Level: advanced

615: .keywords: timestep, pseudo, default

617: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
618: @*/
619: int TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
620: {
621:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
622:   PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
623:   int       ierr;

626:   TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
627:   VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
628:   if (pseudo->initial_fnorm == 0.0) {
629:     /* first time through so compute initial function norm */
630:     pseudo->initial_fnorm = pseudo->fnorm;
631:     fnorm_previous        = pseudo->fnorm;
632:   }
633:   if (pseudo->fnorm == 0.0) {
634:     *newdt = 1.e12*inc*ts->time_step;
635:   } else if (pseudo->increment_dt_from_initial_dt) {
636:     *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm;
637:   } else {
638:     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
639:   }
640:   pseudo->fnorm_previous = pseudo->fnorm;
641:   return(0);
642: }