xref: /petsc/src/ts/impls/pseudo/posindep.c (revision 28aa8177693334f73697128a772045b82fd75ffa)
1 #ifndef lint
2 static char vcid[] = "$Id: posindep.c,v 1.3 1996/09/30 20:23:41 curfman Exp bsmith $";
3 #endif
4 /*
5        Code for Timestepping with implicit backwards Euler.
6 */
7 #include <math.h>
8 #include "src/ts/tsimpl.h"                /*I   "ts.h"   I*/
9 #include "pinclude/pviewer.h"
10 
11 
12 typedef struct {
13   Vec  update;      /* work vector where new solution is formed */
14   Vec  func;        /* work vector where F(t[i],u[i]) is stored */
15   Vec  rhs;         /* work vector for RHS; vec_sol/dt */
16 
17   /* information used for Pseudo-timestepping */
18 
19   int    (*dt)(TS,double*,void*);              /* compute next timestep, and related context */
20   void   *dtctx;
21   int    (*verify)(TS,Vec,void*,double*,int*); /* verify previous timestep and related context */
22   void   *verifyctx;
23 
24   double initial_fnorm,fnorm;                  /* original and current norm of F(u) */
25 
26   double dt_increment;        /* scaling that dt is incremented each time-step */
27 } TS_Pseudo;
28 
29 /* ------------------------------------------------------------------------------*/
30 /*@C
31    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
32    Use with TSPseudoSetTimeStep().
33 
34    Input Parameters:
35 .  ts - the timestep context
36 .  dtctx - unused timestep context
37 
38    Output Parameter:
39 .  newdt - the timestep to use for the next step
40 
41 .keywords: timestep, pseudo, default
42 
43 .seealso: TSPseudoSetTimeStep()
44 @*/
45 int TSPseudoDefaultTimeStep(TS ts,double* newdt,void* dtctx)
46 {
47   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
48   double    inc = pseudo->dt_increment;
49   int       ierr;
50 
51   ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr);
52   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm); CHKERRQ(ierr);
53   if (pseudo->initial_fnorm == 0.0) {
54     /* first time through so compute initial function norm */
55     pseudo->initial_fnorm = pseudo->fnorm;
56   }
57   if (pseudo->fnorm == 0.0) *newdt = 1.e12*inc*ts->time_step;
58   else                      *newdt = inc*ts->time_step*pseudo->initial_fnorm/pseudo->fnorm;
59   return 0;
60 }
61 
62 /*@
63    TSPseudoSetTimeStep - Sets the user-defined routine to be
64    called at each pseudo-timestep to update the timestep.
65 
66    Input Parameters:
67 .  ts - timestep context
68 .  dt - function to compute timestep
69 .  ctx - [optional] context required by function
70 
71 .keywords: timestep, pseudo, set
72 
73 .seealso: TSPseudoDefaultTimeStep()
74 @*/
75 int TSPseudoSetTimeStep(TS ts,int (*dt)(TS,double*,void*),void* ctx)
76 {
77   TS_Pseudo *pseudo;
78 
79   PetscValidHeaderSpecific(ts,TS_COOKIE);
80   if (ts->type != TS_PSEUDO) return 0;
81 
82   pseudo          = (TS_Pseudo*) ts->data;
83   pseudo->dt      = dt;
84   pseudo->dtctx   = ctx;
85   return 0;
86 }
87 
88 /*@
89     TSPseudoComputeTimeStep - Computes the next timestep for a currently running
90     pseudo-timestepping.
91 
92     Input Parameter:
93 .   ts - timestep context
94 
95     Output Parameter:
96 .   dt - newly computed timestep
97 
98 .keywords: timestep, pseudo, compute
99 @*/
100 int TSPseudoComputeTimeStep(TS ts,double *dt)
101 {
102   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
103   int       ierr;
104 
105   PLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);
106   ierr = (*pseudo->dt)(ts,dt, pseudo->dtctx); CHKERRQ(ierr);
107   PLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);
108   return 0;
109 }
110 
111 
112 /* ------------------------------------------------------------------------------*/
113 /*@C
114    TSPseudoDefaultVerifyTimeStep - Default code to verify last timestep.
115 
116    Input Parameters:
117 .  ts - the timestep context
118 .  dtctx - unused timestep context
119 
120    Output Parameter:
121 .  newdt - the timestep to use for the next step
122 
123 @*/
124 int TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void* dtctx,double* newdt,int *flag)
125 {
126   *flag = 1;
127   return 0;
128 }
129 
130 /*@
131    TSPseudoSetVerifyTimeStep - Sets the user routine to verify quality of last timestep.
132 
133    Input Parameters:
134 .  ts - timestep context
135 .  dt - function to verify
136 .  ctx - [optional] context required by function
137 
138 @*/
139 int TSPseudoSetVerifyTimeStep(TS ts,int (*dt)(TS,Vec,void*,double*,int*),void* ctx)
140 {
141   TS_Pseudo *pseudo;
142 
143   PetscValidHeaderSpecific(ts,TS_COOKIE);
144   if (ts->type != TS_PSEUDO) return 0;
145 
146   pseudo              = (TS_Pseudo*) ts->data;
147   pseudo->verify      = dt;
148   pseudo->verifyctx   = ctx;
149   return 0;
150 }
151 
152 /*@
153     TSPseudoVerifyTimeStep - Verifies that the last timestep was OK.
154 
155     Input Parameters:
156 .   ts - timestep context
157 .   update - latest solution
158 
159     Output Parameters:
160 .   dt - newly computed timestep (if it had to shrink)
161 .   flag - indicates if current timestep was ok
162 
163 @*/
164 int TSPseudoVerifyTimeStep(TS ts,Vec update,double *dt,int *flag)
165 {
166   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
167   int       ierr;
168 
169   if (!pseudo->verify) {*flag = 1; return 0;}
170 
171   ierr = (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag ); CHKERRQ(ierr);
172 
173   return 0;
174 }
175 
176 /* --------------------------------------------------------------------------------*/
177 
178 static int TSStep_Pseudo(TS ts,int *steps,double *time)
179 {
180   Vec       sol = ts->vec_sol;
181   int       ierr,i,max_steps = ts->max_steps,its,ok;
182   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
183   double    current_time_step;
184 
185   *steps = -ts->steps;
186 
187   ierr = VecCopy(sol,pseudo->update); CHKERRQ(ierr);
188   for ( i=0; i<max_steps && ts->ptime < ts->max_time; i++ ) {
189     ierr = TSPseudoComputeTimeStep(ts,&ts->time_step); CHKERRQ(ierr);
190     current_time_step = ts->time_step;
191     while (1) {
192       ts->ptime  += current_time_step;
193       ierr = SNESSolve(ts->snes,pseudo->update,&its); CHKERRQ(ierr);
194       ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok); CHKERRQ(ierr);
195       if (ok) break;
196       ts->ptime        -= current_time_step;
197       current_time_step = ts->time_step;
198     }
199     ierr = VecCopy(pseudo->update,sol); CHKERRQ(ierr);
200     ts->steps++;
201     ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr);
202   }
203 
204   *steps += ts->steps;
205   *time  = ts->ptime;
206   return 0;
207 }
208 
209 /*------------------------------------------------------------*/
210 static int TSDestroy_Pseudo(PetscObject obj )
211 {
212   TS        ts = (TS) obj;
213   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
214   int       ierr;
215 
216   ierr = VecDestroy(pseudo->update); CHKERRQ(ierr);
217   if (pseudo->func) {ierr = VecDestroy(pseudo->func);CHKERRQ(ierr);}
218   if (pseudo->rhs)  {ierr = VecDestroy(pseudo->rhs);CHKERRQ(ierr);}
219   if (ts->Ashell)   {ierr = MatDestroy(ts->A); CHKERRQ(ierr);}
220   PetscFree(pseudo);
221   return 0;
222 }
223 
224 
225 /*------------------------------------------------------------*/
226 /*
227     This matrix shell multiply where user provided Shell matrix
228 */
229 
230 int TSPseudoMatMult(Mat mat,Vec x,Vec y)
231 {
232   TS     ts;
233   Scalar mdt,mone = -1.0;
234   int    ierr;
235 
236   MatShellGetContext(mat,(void **)&ts);
237   mdt = 1.0/ts->time_step;
238 
239   /* apply user provided function */
240   ierr = MatMult(ts->Ashell,x,y); CHKERRQ(ierr);
241   /* shift and scale by 1/dt - F */
242   ierr = VecAXPBY(&mdt,&mone,x,y); CHKERRQ(ierr);
243   return 0;
244 }
245 
246 /*
247     This defines the nonlinear equation that is to be solved with SNES
248 
249               (U^{n+1} - U^{n})/dt - F(U^{n+1})
250 */
251 int TSPseudoFunction(SNES snes,Vec x,Vec y,void *ctx)
252 {
253   TS     ts = (TS) ctx;
254   Scalar mdt = 1.0/ts->time_step,*unp1,*un,*Funp1;
255   int    ierr,i,n;
256 
257   /* apply user provided function */
258   ierr = TSComputeRHSFunction(ts,ts->ptime,x,y); CHKERRQ(ierr);
259   /* compute (u^{n+1) - u^{n})/dt - F(u^{n+1}) */
260   ierr = VecGetArray(ts->vec_sol,&un); CHKERRQ(ierr);
261   ierr = VecGetArray(x,&unp1); CHKERRQ(ierr);
262   ierr = VecGetArray(y,&Funp1); CHKERRQ(ierr);
263   ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
264   for ( i=0; i<n; i++ ) {
265     Funp1[i] = mdt*(unp1[i] - un[i]) - Funp1[i];
266   }
267   ierr = VecRestoreArray(ts->vec_sol,&un);
268   ierr = VecRestoreArray(x,&unp1);
269   ierr = VecRestoreArray(y,&Funp1);
270 
271   return 0;
272 }
273 
274 /*
275    This constructs the Jacobian needed for SNES
276 
277              J = I/dt - J_{F}   where J_{F} is the given Jacobian of F.
278 */
279 int TSPseudoJacobian(SNES snes,Vec x,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
280 {
281   TS      ts = (TS) ctx;
282   int     ierr;
283   Scalar  mone = -1.0, mdt = 1.0/ts->time_step;
284   MatType mtype;
285 
286   /* construct users Jacobian */
287   if (ts->rhsjacobian) {
288     ierr = (*ts->rhsjacobian)(ts,ts->ptime,x,AA,BB,str,ts->jacP);CHKERRQ(ierr);
289   }
290 
291   /* shift and scale Jacobian, if not a shell matrix */
292   ierr = MatGetType(*AA,&mtype,PETSC_NULL);
293   if (mtype != MATSHELL) {
294     ierr = MatScale(&mone,*AA); CHKERRQ(ierr);
295     ierr = MatShift(&mdt,*AA); CHKERRQ(ierr);
296   }
297   ierr = MatGetType(*BB,&mtype,PETSC_NULL);
298   if (*BB != *AA && *str != SAME_PRECONDITIONER && mtype != MATSHELL) {
299     ierr = MatScale(&mone,*BB); CHKERRQ(ierr);
300     ierr = MatShift(&mdt,*BB); CHKERRQ(ierr);
301   }
302 
303   return 0;
304 }
305 
306 
307 static int TSSetUp_Pseudo(TS ts)
308 {
309   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
310   int         ierr, M, m;
311 
312   ierr = VecDuplicate(ts->vec_sol,&pseudo->update); CHKERRQ(ierr);
313   ierr = VecDuplicate(ts->vec_sol,&pseudo->func); CHKERRQ(ierr);
314   ierr = SNESSetFunction(ts->snes,pseudo->func,TSPseudoFunction,ts);CHKERRQ(ierr);
315   if (ts->Ashell) { /* construct new shell matrix */
316     ierr = VecGetSize(ts->vec_sol,&M); CHKERRQ(ierr);
317     ierr = VecGetLocalSize(ts->vec_sol,&m); CHKERRQ(ierr);
318     ierr = MatCreateShell(ts->comm,m,M,M,M,ts,&ts->A); CHKERRQ(ierr);
319     ierr = MatShellSetOperation(ts->A,MATOP_MULT,(void*)TSPseudoMatMult);CHKERRQ(ierr);
320   }
321   ierr = SNESSetJacobian(ts->snes,ts->A,ts->B,TSPseudoJacobian,ts);CHKERRQ(ierr);
322   return 0;
323 }
324 /*------------------------------------------------------------*/
325 
326 int TSPseudoDefaultMonitor(TS ts, int step, double time,Vec v, void *ctx)
327 {
328   TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
329 
330   PetscPrintf(ts->comm,"TS %d dt %g time %g fnorm %g\n",step,ts->time_step,time,pseudo->fnorm);
331   return 0;
332 }
333 
334 static int TSSetFromOptions_Pseudo(TS ts)
335 {
336   int    ierr,flg;
337   double inc;
338 
339   ierr = SNESSetFromOptions(ts->snes); CHKERRQ(ierr);
340 
341   ierr = OptionsHasName(ts->prefix,"-ts_monitor",&flg); CHKERRQ(ierr);
342   if (flg) {
343     ierr = TSSetMonitor(ts,TSPseudoDefaultMonitor,0); CHKERRQ(ierr);
344   }
345   ierr = OptionsGetDouble(ts->prefix,"-ts_pseudo_increment",&inc,&flg);  CHKERRQ(ierr);
346   if (flg) {
347     ierr = TSPseudoSetTimeStepIncrement(ts,inc);  CHKERRQ(ierr);
348   }
349   return 0;
350 }
351 
352 static int TSPrintHelp_Pseudo(TS ts)
353 {
354 
355   return 0;
356 }
357 
358 static int TSView_Pseudo(PetscObject obj,Viewer viewer)
359 {
360   return 0;
361 }
362 
363 /* ------------------------------------------------------------ */
364 int TSCreate_Pseudo(TS ts )
365 {
366   TS_Pseudo *pseudo;
367   int       ierr;
368   MatType   mtype;
369 
370   ts->type 	      = TS_PSEUDO;
371   ts->destroy         = TSDestroy_Pseudo;
372   ts->printhelp       = TSPrintHelp_Pseudo;
373   ts->view            = TSView_Pseudo;
374 
375   if (ts->problem_type == TS_LINEAR) {
376     SETERRQ(1,"TSCreate_Pseudo:Only for nonlinear problems");
377   }
378   if (!ts->A) {
379     SETERRQ(1,"TSCreate_Pseudo:Must set Jacobian");
380   }
381   ierr = MatGetType(ts->A,&mtype,PETSC_NULL);
382   if (mtype == MATSHELL) {
383     ts->Ashell = ts->A;
384   }
385   ts->setup           = TSSetUp_Pseudo;
386   ts->step            = TSStep_Pseudo;
387   ts->setfromoptions  = TSSetFromOptions_Pseudo;
388 
389   /* create the required nonlinear solver context */
390   ierr = SNESCreate(ts->comm,SNES_NONLINEAR_EQUATIONS,&ts->snes);CHKERRQ(ierr);
391 
392   pseudo   = PetscNew(TS_Pseudo); CHKPTRQ(pseudo);
393   PetscMemzero(pseudo,sizeof(TS_Pseudo));
394   ts->data = (void *) pseudo;
395 
396   pseudo->dt_increment = 1.1;
397   pseudo->dt           = TSPseudoDefaultTimeStep;
398   return 0;
399 }
400 
401 
402 /*@
403       TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
404          dt when using the TSPseudoDefaultTimeStep() routine.
405 
406   Input Parameters:
407 .   ts - the timestep context
408 .   inc - the scaling factor >= 1.0
409 
410    Options Database Key:
411 $  -ts_pseudo_increment <increment>
412 
413 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
414 @*/
415 int TSPseudoSetTimeStepIncrement(TS ts,double inc)
416 {
417   TS_Pseudo *pseudo;
418 
419   PetscValidHeaderSpecific(ts,TS_COOKIE);
420   if (ts->type != TS_PSEUDO) return 0;
421 
422   pseudo               = (TS_Pseudo*) ts->data;
423   pseudo->dt_increment = inc;
424   return 0;
425 }
426 
427 
428 
429