Actual source code: posindep.c
1: #define PETSCTS_DLL
3: /*
4: Code for Timestepping with implicit backwards Euler.
5: */
6: #include 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;
60: (*pseudo->dt)(ts,dt,pseudo->dtctx);
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(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(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(ts->comm,&ts->snes);
574: PetscNew(TS_Pseudo,&pseudo);
575: PetscLogObjectMemory(ts,sizeof(TS_Pseudo));
577: PetscMemzero(pseudo,sizeof(TS_Pseudo));
578: ts->data = (void*)pseudo;
580: pseudo->dt_increment = 1.1;
581: pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
582: pseudo->dt = TSPseudoDefaultTimeStep;
584: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
585: "TSPseudoSetVerifyTimeStep_Pseudo",
586: TSPseudoSetVerifyTimeStep_Pseudo);
587: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
588: "TSPseudoSetTimeStepIncrement_Pseudo",
589: TSPseudoSetTimeStepIncrement_Pseudo);
590: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
591: "TSPseudoIncrementDtFromInitialDt_Pseudo",
592: TSPseudoIncrementDtFromInitialDt_Pseudo);
593: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
594: "TSPseudoSetTimeStep_Pseudo",
595: TSPseudoSetTimeStep_Pseudo);
596: return(0);
597: }
602: /*@C
603: TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
604: Use with TSPseudoSetTimeStep().
606: Collective on TS
608: Input Parameters:
609: . ts - the timestep context
610: . dtctx - unused timestep context
612: Output Parameter:
613: . newdt - the timestep to use for the next step
615: Level: advanced
617: .keywords: timestep, pseudo, default
619: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
620: @*/
621: PetscErrorCode TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
622: {
623: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
624: PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
628: TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
629: VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
630: if (pseudo->initial_fnorm == 0.0) {
631: /* first time through so compute initial function norm */
632: pseudo->initial_fnorm = pseudo->fnorm;
633: fnorm_previous = pseudo->fnorm;
634: }
635: if (pseudo->fnorm == 0.0) {
636: *newdt = 1.e12*inc*ts->time_step;
637: } else if (pseudo->increment_dt_from_initial_dt) {
638: *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm;
639: } else {
640: *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
641: }
642: pseudo->fnorm_previous = pseudo->fnorm;
643: return(0);
644: }