Actual source code: posindep.c

  1: #define PETSCTS_DLL

  3: /*
  4:        Code for Timestepping with implicit backwards Euler.
  5: */
 6:  #include private/tsimpl.h

  8: typedef struct {
  9:   Vec  update;      /* work vector where new solution is formed */
 10:   Vec  func;        /* work vector where F(t[i],u[i]) is stored */
 11:   Vec  rhs;         /* work vector for RHS; vec_sol/dt */

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

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

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

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

 27: /* ------------------------------------------------------------------------------*/

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

 35:     Collective on TS

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

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

 43:     Level: advanced

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

 49: .keywords: timestep, pseudo, compute

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

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


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

 72:    Collective on TS

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

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

 83:    Level: advanced

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

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

 91: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
 92: @*/
 93: PetscErrorCode  TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscTruth *flag)
 94: {
 96:   *flag = PETSC_TRUE;
 97:   return(0);
 98: }


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

106:     Collective on TS

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

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

116:     Level: advanced

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

122: .keywords: timestep, pseudo, verify 

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

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

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

136:   return(0);
137: }

139: /* --------------------------------------------------------------------------------*/

143: static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime)
144: {
145:   Vec            sol = ts->vec_sol;
147:   PetscInt       i,max_steps = ts->max_steps,its,lits;
148:   PetscTruth     ok;
149:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
150:   PetscReal      current_time_step;
151: 
153:   *steps = -ts->steps;

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

178:   *steps += ts->steps;
179:   *ptime  = ts->ptime;
180:   return(0);
181: }

183: /*------------------------------------------------------------*/
186: static PetscErrorCode TSDestroy_Pseudo(TS ts)
187: {
188:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

192:   if (pseudo->update) {VecDestroy(pseudo->update);}
193:   if (pseudo->func) {VecDestroy(pseudo->func);}
194:   if (pseudo->rhs)  {VecDestroy(pseudo->rhs);}
195:   PetscFree(pseudo);
196:   return(0);
197: }


200: /*------------------------------------------------------------*/

202: /* 
203:     This defines the nonlinear equation that is to be solved with SNES

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

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

233: /*
234:    This constructs the Jacobian needed for SNES 

236:              J = I/dt - J_{F}   where J_{F} is the given Jacobian of F.
237: */
240: PetscErrorCode TSPseudoJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
241: {
242:   TS             ts = (TS) ctx;

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

249:   /* shift and scale Jacobian */
250:   TSScaleShiftMatrices(ts,*AA,*BB,*str);
251:   return(0);
252: }


257: static PetscErrorCode TSSetUp_Pseudo(TS ts)
258: {
259:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

263:   VecDuplicate(ts->vec_sol,&pseudo->update);
264:   VecDuplicate(ts->vec_sol,&pseudo->func);
265:   SNESSetFunction(ts->snes,pseudo->func,TSPseudoFunction,ts);
266:   SNESSetJacobian(ts->snes,ts->Arhs,ts->B,TSPseudoJacobian,ts);
267:   return(0);
268: }
269: /*------------------------------------------------------------*/

273: PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx)
274: {
275:   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
276:   PetscErrorCode          ierr;
277:   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx;

280:   if (!ctx) {
281:     PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);
282:   }
283:   PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);
284:   if (!ctx) {
285:     PetscViewerASCIIMonitorDestroy(viewer);
286:   }
287:   return(0);
288: }

292: static PetscErrorCode TSSetFromOptions_Pseudo(TS ts)
293: {
294:   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
295:   PetscErrorCode          ierr;
296:   PetscTruth              flg;
297:   PetscViewerASCIIMonitor viewer;

300:   PetscOptionsHead("Pseudo-timestepping options");
301:     PetscOptionsName("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",&flg);
302:     if (flg) {
303:       PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);
304:       TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);
305:     }
306:     PetscOptionsName("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",&flg);
307:     if (flg) {
308:       TSPseudoIncrementDtFromInitialDt(ts);
309:     }
310:     PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);
311:   PetscOptionsTail();
312:   return(0);
313: }

317: static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
318: {
320:   return(0);
321: }

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

330:    Collective on TS

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

338:    Level: advanced

340:    Calling sequence of func:
341: .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag);

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

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

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

354: .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
355: @*/
356: PetscErrorCode  TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx)
357: {
358:   PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *);


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

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: PetscErrorCode  TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
392: {
393:   PetscErrorCode ierr,(*f)(TS,PetscReal);


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

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

414:    Collective on TS

416:     Input Parameter:
417: .   ts - the timestep context

419:     Options Database Key:
420: $    -ts_pseudo_increment_dt_from_initial_dt

422:     Level: advanced

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

426: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
427: @*/
428: PetscErrorCode  TSPseudoIncrementDtFromInitialDt(TS ts)
429: {
430:   PetscErrorCode ierr,(*f)(TS);


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


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

449:    Collective on TS

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

457:    Level: intermediate

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

462: .  newdt - the newly computed timestep
463: .  ctx - [optional] timestep context

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

469: .keywords: timestep, pseudo, set

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


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

487: /* ----------------------------------------------------------------------------- */

493: PetscErrorCode  TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
494: {
495:   TS_Pseudo *pseudo;

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

508: PetscErrorCode  TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
509: {
510:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

513:   pseudo->dt_increment = inc;
514:   return(0);
515: }

521: PetscErrorCode  TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
522: {
523:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

526:   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
527:   return(0);
528: }

535: PetscErrorCode  TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
536: {
537:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

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

546: /* ----------------------------------------------------------------------------- */

551: PetscErrorCode  TSCreate_Pseudo(TS ts)
552: {
553:   TS_Pseudo      *pseudo;

557:   ts->ops->destroy         = TSDestroy_Pseudo;
558:   ts->ops->view            = TSView_Pseudo;

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

567:   ts->ops->setup           = TSSetUp_Pseudo;
568:   ts->ops->step            = TSStep_Pseudo;
569:   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;

571:   /* create the required nonlinear solver context */
572:   SNESCreate(((PetscObject)ts)->comm,&ts->snes);
573:   PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);

575:   PetscNewLog(ts,TS_Pseudo,&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: }

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: PetscErrorCode  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;

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