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