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