1 2 /* 3 Code for Timestepping with implicit backwards Euler. 4 */ 5 #include "private/tsimpl.h" /*I "petscts.h" I*/ 6 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 xdot; /* work vector for time derivative of state */ 11 12 /* information used for Pseudo-timestepping */ 13 14 PetscErrorCode (*dt)(TS,PetscReal*,void*); /* compute next timestep, and related context */ 15 void *dtctx; 16 PetscErrorCode (*verify)(TS,Vec,void*,PetscReal*,PetscBool *); /* verify previous timestep and related context */ 17 void *verifyctx; 18 19 PetscReal initial_fnorm,fnorm; /* original and current norm of F(u) */ 20 PetscReal fnorm_previous; 21 22 PetscReal dt_increment; /* scaling that dt is incremented each time-step */ 23 PetscBool increment_dt_from_initial_dt; 24 } TS_Pseudo; 25 26 /* ------------------------------------------------------------------------------*/ 27 28 #undef __FUNCT__ 29 #define __FUNCT__ "TSPseudoComputeTimeStep" 30 /*@ 31 TSPseudoComputeTimeStep - Computes the next timestep for a currently running 32 pseudo-timestepping process. 33 34 Collective on TS 35 36 Input Parameter: 37 . ts - timestep context 38 39 Output Parameter: 40 . dt - newly computed timestep 41 42 Level: advanced 43 44 Notes: 45 The routine to be called here to compute the timestep should be 46 set by calling TSPseudoSetTimeStep(). 47 48 .keywords: timestep, pseudo, compute 49 50 .seealso: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep() 51 @*/ 52 PetscErrorCode TSPseudoComputeTimeStep(TS ts,PetscReal *dt) 53 { 54 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 55 PetscErrorCode ierr; 56 57 PetscFunctionBegin; 58 ierr = PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 59 ierr = (*pseudo->dt)(ts,dt,pseudo->dtctx);CHKERRQ(ierr); 60 ierr = PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 61 PetscFunctionReturn(0); 62 } 63 64 65 /* ------------------------------------------------------------------------------*/ 66 #undef __FUNCT__ 67 #define __FUNCT__ "TSPseudoDefaultVerifyTimeStep" 68 /*@C 69 TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep. 70 71 Collective on TS 72 73 Input Parameters: 74 + ts - the timestep context 75 . dtctx - unused timestep context 76 - update - latest solution vector 77 78 Output Parameters: 79 + newdt - the timestep to use for the next step 80 - flag - flag indicating whether the last time step was acceptable 81 82 Level: advanced 83 84 Note: 85 This routine always returns a flag of 1, indicating an acceptable 86 timestep. 87 88 .keywords: timestep, pseudo, default, verify 89 90 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep() 91 @*/ 92 PetscErrorCode TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscBool *flag) 93 { 94 PetscFunctionBegin; 95 *flag = PETSC_TRUE; 96 PetscFunctionReturn(0); 97 } 98 99 100 #undef __FUNCT__ 101 #define __FUNCT__ "TSPseudoVerifyTimeStep" 102 /*@ 103 TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable. 104 105 Collective on TS 106 107 Input Parameters: 108 + ts - timestep context 109 - update - latest solution vector 110 111 Output Parameters: 112 + dt - newly computed timestep (if it had to shrink) 113 - flag - indicates if current timestep was ok 114 115 Level: advanced 116 117 Notes: 118 The routine to be called here to compute the timestep should be 119 set by calling TSPseudoSetVerifyTimeStep(). 120 121 .keywords: timestep, pseudo, verify 122 123 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep() 124 @*/ 125 PetscErrorCode TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscBool *flag) 126 { 127 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 128 PetscErrorCode ierr; 129 130 PetscFunctionBegin; 131 if (!pseudo->verify) {*flag = PETSC_TRUE; PetscFunctionReturn(0);} 132 133 ierr = (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);CHKERRQ(ierr); 134 135 PetscFunctionReturn(0); 136 } 137 138 /* --------------------------------------------------------------------------------*/ 139 140 #undef __FUNCT__ 141 #define __FUNCT__ "TSStep_Pseudo" 142 static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime) 143 { 144 Vec sol = ts->vec_sol; 145 PetscErrorCode ierr; 146 PetscInt i,max_steps = ts->max_steps,its,lits; 147 PetscBool ok; 148 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 149 PetscReal current_time_step; 150 151 PetscFunctionBegin; 152 *steps = -ts->steps; 153 154 ierr = VecCopy(sol,pseudo->update);CHKERRQ(ierr); 155 for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) { 156 ierr = TSPseudoComputeTimeStep(ts,&ts->time_step);CHKERRQ(ierr); 157 ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr); 158 current_time_step = ts->time_step; 159 ierr = TSPreStep(ts);CHKERRQ(ierr); 160 while (PETSC_TRUE) { 161 ts->ptime += current_time_step; 162 ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr); 163 ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr); 164 ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr); 165 ts->nonlinear_its += its; ts->linear_its += lits; 166 ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);CHKERRQ(ierr); 167 if (ok) break; 168 ts->ptime -= current_time_step; 169 current_time_step = ts->time_step; 170 } 171 ierr = VecCopy(pseudo->update,sol);CHKERRQ(ierr); 172 ts->steps++; 173 ierr = TSPostStep(ts);CHKERRQ(ierr); 174 } 175 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 176 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func);CHKERRQ(ierr); 177 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 178 ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr); 179 180 *steps += ts->steps; 181 *ptime = ts->ptime; 182 PetscFunctionReturn(0); 183 } 184 185 /*------------------------------------------------------------*/ 186 #undef __FUNCT__ 187 #define __FUNCT__ "TSDestroy_Pseudo" 188 static PetscErrorCode TSDestroy_Pseudo(TS ts) 189 { 190 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 191 PetscErrorCode ierr; 192 193 PetscFunctionBegin; 194 if (pseudo->update) {ierr = VecDestroy(pseudo->update);CHKERRQ(ierr);} 195 if (pseudo->func) {ierr = VecDestroy(pseudo->func);CHKERRQ(ierr);} 196 if (pseudo->xdot) {ierr = VecDestroy(pseudo->xdot);CHKERRQ(ierr);} 197 ierr = PetscFree(ts->data);CHKERRQ(ierr); 198 PetscFunctionReturn(0); 199 } 200 201 202 /*------------------------------------------------------------*/ 203 204 #undef __FUNCT__ 205 #define __FUNCT__ "TSPseudoGetXdot" 206 /* 207 Compute Xdot = (X^{n+1}-X^n)/dt) = 0 208 */ 209 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot) 210 { 211 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 212 PetscScalar mdt = 1.0/ts->time_step,*xnp1,*xn,*xdot; 213 PetscErrorCode ierr; 214 PetscInt i,n; 215 216 PetscFunctionBegin; 217 ierr = VecGetArray(ts->vec_sol,&xn);CHKERRQ(ierr); 218 ierr = VecGetArray(X,&xnp1);CHKERRQ(ierr); 219 ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 220 ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr); 221 for (i=0; i<n; i++) { 222 xdot[i] = mdt*(xnp1[i] - xn[i]); 223 } 224 ierr = VecRestoreArray(ts->vec_sol,&xn);CHKERRQ(ierr); 225 ierr = VecRestoreArray(X,&xnp1);CHKERRQ(ierr); 226 ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 227 *Xdot = pseudo->xdot; 228 PetscFunctionReturn(0); 229 } 230 231 #undef __FUNCT__ 232 #define __FUNCT__ "SNESTSFormFunction_Pseudo" 233 /* 234 The transient residual is 235 236 F(U^{n+1},(U^{n+1}-U^n)/dt) = 0 237 238 or for ODE, 239 240 (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0 241 242 This is the function that must be evaluated for transient simulation and for 243 finite difference Jacobians. On the first Newton step, this algorithm uses 244 a guess of U^{n+1} = U^n in which case the transient term vanishes and the 245 residual is actually the steady state residual. Pseudotransient 246 continuation as described in the literature is a linearly implicit 247 algorithm, it only takes this one Newton step with the steady state 248 residual, and then advances to the next time step. 249 */ 250 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts) 251 { 252 Vec Xdot; 253 PetscErrorCode ierr; 254 255 PetscFunctionBegin; 256 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 257 ierr = TSComputeIFunction(ts,ts->ptime,X,Xdot,Y);CHKERRQ(ierr); 258 PetscFunctionReturn(0); 259 } 260 261 #undef __FUNCT__ 262 #define __FUNCT__ "SNESTSFormJacobian_Pseudo" 263 /* 264 This constructs the Jacobian needed for SNES. For DAE, this is 265 266 dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot 267 268 and for ODE: 269 270 J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs. 271 */ 272 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts) 273 { 274 Vec Xdot; 275 PetscErrorCode ierr; 276 277 PetscFunctionBegin; 278 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 279 ierr = TSComputeIJacobian(ts,ts->ptime,X,Xdot,1./ts->time_step,AA,BB,str);CHKERRQ(ierr); 280 PetscFunctionReturn(0); 281 } 282 283 284 #undef __FUNCT__ 285 #define __FUNCT__ "TSSetUp_Pseudo" 286 static PetscErrorCode TSSetUp_Pseudo(TS ts) 287 { 288 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 289 PetscErrorCode ierr; 290 291 PetscFunctionBegin; 292 ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr); 293 ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr); 294 ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr); 295 ierr = SNESSetFunction(ts->snes,pseudo->func,SNESTSFormFunction,ts);CHKERRQ(ierr); 296 /* This is nasty. SNESSetFromOptions() is usually called in TSSetFromOptions(). With -snes_mf_operator, it will 297 replace A and we don't want to mess with that. With -snes_mf, A and B will be replaced as well as the function and 298 context. Note that SNESSetFunction() normally has not been called before SNESSetFromOptions(), so when -snes_mf sets 299 the Jacobian user context to snes->funP, it will actually be NULL. This is not a problem because both snes->funP and 300 snes->jacP should be the TS. */ 301 { 302 Mat A,B; 303 PetscErrorCode (*func)(SNES,Vec,Mat*,Mat*,MatStructure*,void*); 304 void *ctx; 305 ierr = SNESGetJacobian(ts->snes,&A,&B,&func,&ctx);CHKERRQ(ierr); 306 ierr = SNESSetJacobian(ts->snes,A?A:ts->A,B?B:ts->B,func?func:SNESTSFormJacobian,ctx?ctx:ts);CHKERRQ(ierr); 307 } 308 PetscFunctionReturn(0); 309 } 310 /*------------------------------------------------------------*/ 311 312 #undef __FUNCT__ 313 #define __FUNCT__ "TSPseudoMonitorDefault" 314 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx) 315 { 316 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 317 PetscErrorCode ierr; 318 PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx; 319 320 PetscFunctionBegin; 321 if (!ctx) { 322 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 323 } 324 ierr = PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr); 325 if (!ctx) { 326 ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr); 327 } 328 PetscFunctionReturn(0); 329 } 330 331 #undef __FUNCT__ 332 #define __FUNCT__ "TSSetFromOptions_Pseudo" 333 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts) 334 { 335 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 336 PetscErrorCode ierr; 337 PetscBool flg = PETSC_FALSE; 338 PetscViewerASCIIMonitor viewer; 339 340 PetscFunctionBegin; 341 ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr); 342 ierr = PetscOptionsBool("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 343 if (flg) { 344 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 345 ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 346 } 347 flg = PETSC_FALSE; 348 ierr = PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 349 if (flg) { 350 ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr); 351 } 352 ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr); 353 ierr = PetscOptionsTail();CHKERRQ(ierr); 354 PetscFunctionReturn(0); 355 } 356 357 #undef __FUNCT__ 358 #define __FUNCT__ "TSView_Pseudo" 359 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer) 360 { 361 PetscFunctionBegin; 362 PetscFunctionReturn(0); 363 } 364 365 /* ----------------------------------------------------------------------------- */ 366 #undef __FUNCT__ 367 #define __FUNCT__ "TSPseudoSetVerifyTimeStep" 368 /*@C 369 TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 370 last timestep. 371 372 Logically Collective on TS 373 374 Input Parameters: 375 + ts - timestep context 376 . dt - user-defined function to verify timestep 377 - ctx - [optional] user-defined context for private data 378 for the timestep verification routine (may be PETSC_NULL) 379 380 Level: advanced 381 382 Calling sequence of func: 383 . func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscBool *flag); 384 385 . update - latest solution vector 386 . ctx - [optional] timestep context 387 . newdt - the timestep to use for the next step 388 . flag - flag indicating whether the last time step was acceptable 389 390 Notes: 391 The routine set here will be called by TSPseudoVerifyTimeStep() 392 during the timestepping process. 393 394 .keywords: timestep, pseudo, set, verify 395 396 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep() 397 @*/ 398 PetscErrorCode TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscBool *),void* ctx) 399 { 400 PetscErrorCode ierr; 401 402 PetscFunctionBegin; 403 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 404 ierr = PetscTryMethod(ts,"TSPseudoSetVerifyTimeStep_C",(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscBool *),void *),(ts,dt,ctx));CHKERRQ(ierr); 405 PetscFunctionReturn(0); 406 } 407 408 #undef __FUNCT__ 409 #define __FUNCT__ "TSPseudoSetTimeStepIncrement" 410 /*@ 411 TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to 412 dt when using the TSPseudoDefaultTimeStep() routine. 413 414 Logically Collective on TS 415 416 Input Parameters: 417 + ts - the timestep context 418 - inc - the scaling factor >= 1.0 419 420 Options Database Key: 421 $ -ts_pseudo_increment <increment> 422 423 Level: advanced 424 425 .keywords: timestep, pseudo, set, increment 426 427 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 428 @*/ 429 PetscErrorCode TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc) 430 { 431 PetscErrorCode ierr; 432 433 PetscFunctionBegin; 434 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 435 PetscValidLogicalCollectiveReal(ts,inc,2); 436 ierr = PetscTryMethod(ts,"TSPseudoSetTimeStepIncrement_C",(TS,PetscReal),(ts,inc));CHKERRQ(ierr); 437 PetscFunctionReturn(0); 438 } 439 440 #undef __FUNCT__ 441 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt" 442 /*@ 443 TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep 444 is computed via the formula 445 $ dt = initial_dt*initial_fnorm/current_fnorm 446 rather than the default update, 447 $ dt = current_dt*previous_fnorm/current_fnorm. 448 449 Logically Collective on TS 450 451 Input Parameter: 452 . ts - the timestep context 453 454 Options Database Key: 455 $ -ts_pseudo_increment_dt_from_initial_dt 456 457 Level: advanced 458 459 .keywords: timestep, pseudo, set, increment 460 461 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 462 @*/ 463 PetscErrorCode TSPseudoIncrementDtFromInitialDt(TS ts) 464 { 465 PetscErrorCode ierr; 466 467 PetscFunctionBegin; 468 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 469 ierr = PetscTryMethod(ts,"TSPseudoIncrementDtFromInitialDt_C",(TS),(ts));CHKERRQ(ierr); 470 PetscFunctionReturn(0); 471 } 472 473 474 #undef __FUNCT__ 475 #define __FUNCT__ "TSPseudoSetTimeStep" 476 /*@C 477 TSPseudoSetTimeStep - Sets the user-defined routine to be 478 called at each pseudo-timestep to update the timestep. 479 480 Logically Collective on TS 481 482 Input Parameters: 483 + ts - timestep context 484 . dt - function to compute timestep 485 - ctx - [optional] user-defined context for private data 486 required by the function (may be PETSC_NULL) 487 488 Level: intermediate 489 490 Calling sequence of func: 491 . func (TS ts,PetscReal *newdt,void *ctx); 492 493 . newdt - the newly computed timestep 494 . ctx - [optional] timestep context 495 496 Notes: 497 The routine set here will be called by TSPseudoComputeTimeStep() 498 during the timestepping process. 499 500 .keywords: timestep, pseudo, set 501 502 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep() 503 @*/ 504 PetscErrorCode TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx) 505 { 506 PetscErrorCode ierr; 507 508 PetscFunctionBegin; 509 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 510 ierr = PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *),(ts,dt,ctx));CHKERRQ(ierr); 511 PetscFunctionReturn(0); 512 } 513 514 /* ----------------------------------------------------------------------------- */ 515 516 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool *); /* force argument to next function to not be extern C*/ 517 EXTERN_C_BEGIN 518 #undef __FUNCT__ 519 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo" 520 PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx) 521 { 522 TS_Pseudo *pseudo; 523 524 PetscFunctionBegin; 525 pseudo = (TS_Pseudo*)ts->data; 526 pseudo->verify = dt; 527 pseudo->verifyctx = ctx; 528 PetscFunctionReturn(0); 529 } 530 EXTERN_C_END 531 532 EXTERN_C_BEGIN 533 #undef __FUNCT__ 534 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 535 PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 536 { 537 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 538 539 PetscFunctionBegin; 540 pseudo->dt_increment = inc; 541 PetscFunctionReturn(0); 542 } 543 EXTERN_C_END 544 545 EXTERN_C_BEGIN 546 #undef __FUNCT__ 547 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 548 PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 549 { 550 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 551 552 PetscFunctionBegin; 553 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 554 PetscFunctionReturn(0); 555 } 556 EXTERN_C_END 557 558 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 559 EXTERN_C_BEGIN 560 #undef __FUNCT__ 561 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 562 PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx) 563 { 564 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 565 566 PetscFunctionBegin; 567 pseudo->dt = dt; 568 pseudo->dtctx = ctx; 569 PetscFunctionReturn(0); 570 } 571 EXTERN_C_END 572 573 /* ----------------------------------------------------------------------------- */ 574 /*MC 575 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 576 577 This method solves equations of the form 578 579 $ F(X,Xdot) = 0 580 581 for steady state using the iteration 582 583 $ [G'] S = -F(X,0) 584 $ X += S 585 586 where 587 588 $ G(Y) = F(Y,(Y-X)/dt) 589 590 This is linearly-implicit Euler with the residual always evaluated "at steady 591 state". See note below. 592 593 Options database keys: 594 + -ts_pseudo_increment <real> - ratio of increase dt 595 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 596 597 Level: beginner 598 599 References: 600 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 601 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 602 603 Notes: 604 The residual computed by this method includes the transient term (Xdot is computed instead of 605 always being zero), but since the prediction from the last step is always the solution from the 606 last step, on the first Newton iteration we have 607 608 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 609 610 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 611 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 612 algorithm is no longer the one described in the referenced papers. 613 614 .seealso: TSCreate(), TS, TSSetType() 615 616 M*/ 617 EXTERN_C_BEGIN 618 #undef __FUNCT__ 619 #define __FUNCT__ "TSCreate_Pseudo" 620 PetscErrorCode TSCreate_Pseudo(TS ts) 621 { 622 TS_Pseudo *pseudo; 623 PetscErrorCode ierr; 624 625 PetscFunctionBegin; 626 ts->ops->destroy = TSDestroy_Pseudo; 627 ts->ops->view = TSView_Pseudo; 628 629 if (ts->problem_type == TS_LINEAR) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Only for nonlinear problems"); 630 ts->ops->setup = TSSetUp_Pseudo; 631 ts->ops->step = TSStep_Pseudo; 632 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 633 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 634 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 635 636 /* create the required nonlinear solver context */ 637 ierr = SNESCreate(((PetscObject)ts)->comm,&ts->snes);CHKERRQ(ierr); 638 ierr = PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);CHKERRQ(ierr); 639 640 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 641 ts->data = (void*)pseudo; 642 643 pseudo->dt_increment = 1.1; 644 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 645 pseudo->dt = TSPseudoDefaultTimeStep; 646 647 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C", 648 "TSPseudoSetVerifyTimeStep_Pseudo", 649 TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 650 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C", 651 "TSPseudoSetTimeStepIncrement_Pseudo", 652 TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 653 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C", 654 "TSPseudoIncrementDtFromInitialDt_Pseudo", 655 TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 656 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C", 657 "TSPseudoSetTimeStep_Pseudo", 658 TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 659 PetscFunctionReturn(0); 660 } 661 EXTERN_C_END 662 663 #undef __FUNCT__ 664 #define __FUNCT__ "TSPseudoDefaultTimeStep" 665 /*@C 666 TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping. 667 Use with TSPseudoSetTimeStep(). 668 669 Collective on TS 670 671 Input Parameters: 672 . ts - the timestep context 673 . dtctx - unused timestep context 674 675 Output Parameter: 676 . newdt - the timestep to use for the next step 677 678 Level: advanced 679 680 .keywords: timestep, pseudo, default 681 682 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 683 @*/ 684 PetscErrorCode TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx) 685 { 686 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 687 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 688 PetscErrorCode ierr; 689 690 PetscFunctionBegin; 691 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 692 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func);CHKERRQ(ierr); 693 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 694 if (pseudo->initial_fnorm == 0.0) { 695 /* first time through so compute initial function norm */ 696 pseudo->initial_fnorm = pseudo->fnorm; 697 fnorm_previous = pseudo->fnorm; 698 } 699 if (pseudo->fnorm == 0.0) { 700 *newdt = 1.e12*inc*ts->time_step; 701 } else if (pseudo->increment_dt_from_initial_dt) { 702 *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm; 703 } else { 704 *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 705 } 706 pseudo->fnorm_previous = pseudo->fnorm; 707 PetscFunctionReturn(0); 708 } 709