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