1 #define PETSCTS_DLL 2 3 /* 4 Code for Timestepping with implicit backwards Euler. 5 */ 6 #include "private/tsimpl.h" /*I "petscts.h" I*/ 7 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 xdot; /* work vector for time derivative of state */ 12 13 /* information used for Pseudo-timestepping */ 14 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; 19 20 PetscReal initial_fnorm,fnorm; /* original and current norm of F(u) */ 21 PetscReal fnorm_previous; 22 23 PetscReal dt_increment; /* scaling that dt is incremented each time-step */ 24 PetscTruth increment_dt_from_initial_dt; 25 } TS_Pseudo; 26 27 /* ------------------------------------------------------------------------------*/ 28 29 #undef __FUNCT__ 30 #define __FUNCT__ "TSPseudoComputeTimeStep" 31 /*@ 32 TSPseudoComputeTimeStep - Computes the next timestep for a currently running 33 pseudo-timestepping process. 34 35 Collective on TS 36 37 Input Parameter: 38 . ts - timestep context 39 40 Output Parameter: 41 . dt - newly computed timestep 42 43 Level: advanced 44 45 Notes: 46 The routine to be called here to compute the timestep should be 47 set by calling TSPseudoSetTimeStep(). 48 49 .keywords: timestep, pseudo, compute 50 51 .seealso: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep() 52 @*/ 53 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoComputeTimeStep(TS ts,PetscReal *dt) 54 { 55 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 56 PetscErrorCode ierr; 57 58 PetscFunctionBegin; 59 ierr = PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 60 ierr = (*pseudo->dt)(ts,dt,pseudo->dtctx);CHKERRQ(ierr); 61 ierr = PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 62 PetscFunctionReturn(0); 63 } 64 65 66 /* ------------------------------------------------------------------------------*/ 67 #undef __FUNCT__ 68 #define __FUNCT__ "TSPseudoDefaultVerifyTimeStep" 69 /*@C 70 TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep. 71 72 Collective on TS 73 74 Input Parameters: 75 + ts - the timestep context 76 . dtctx - unused timestep context 77 - update - latest solution vector 78 79 Output Parameters: 80 + newdt - the timestep to use for the next step 81 - flag - flag indicating whether the last time step was acceptable 82 83 Level: advanced 84 85 Note: 86 This routine always returns a flag of 1, indicating an acceptable 87 timestep. 88 89 .keywords: timestep, pseudo, default, verify 90 91 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep() 92 @*/ 93 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscTruth *flag) 94 { 95 PetscFunctionBegin; 96 *flag = PETSC_TRUE; 97 PetscFunctionReturn(0); 98 } 99 100 101 #undef __FUNCT__ 102 #define __FUNCT__ "TSPseudoVerifyTimeStep" 103 /*@ 104 TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable. 105 106 Collective on TS 107 108 Input Parameters: 109 + ts - timestep context 110 - update - latest solution vector 111 112 Output Parameters: 113 + dt - newly computed timestep (if it had to shrink) 114 - flag - indicates if current timestep was ok 115 116 Level: advanced 117 118 Notes: 119 The routine to be called here to compute the timestep should be 120 set by calling TSPseudoSetVerifyTimeStep(). 121 122 .keywords: timestep, pseudo, verify 123 124 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep() 125 @*/ 126 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscTruth *flag) 127 { 128 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 129 PetscErrorCode ierr; 130 131 PetscFunctionBegin; 132 if (!pseudo->verify) {*flag = PETSC_TRUE; PetscFunctionReturn(0);} 133 134 ierr = (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);CHKERRQ(ierr); 135 136 PetscFunctionReturn(0); 137 } 138 139 /* --------------------------------------------------------------------------------*/ 140 141 #undef __FUNCT__ 142 #define __FUNCT__ "TSStep_Pseudo" 143 static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime) 144 { 145 Vec sol = ts->vec_sol; 146 PetscErrorCode ierr; 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 152 PetscFunctionBegin; 153 *steps = -ts->steps; 154 155 ierr = VecCopy(sol,pseudo->update);CHKERRQ(ierr); 156 for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) { 157 ierr = TSPseudoComputeTimeStep(ts,&ts->time_step);CHKERRQ(ierr); 158 ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr); 159 current_time_step = ts->time_step; 160 ierr = TSPreStep(ts);CHKERRQ(ierr); 161 while (PETSC_TRUE) { 162 ts->ptime += current_time_step; 163 ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr); 164 ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr); 165 ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr); 166 ts->nonlinear_its += its; ts->linear_its += lits; 167 ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);CHKERRQ(ierr); 168 if (ok) break; 169 ts->ptime -= current_time_step; 170 current_time_step = ts->time_step; 171 } 172 ierr = VecCopy(pseudo->update,sol);CHKERRQ(ierr); 173 ts->steps++; 174 ierr = TSPostStep(ts);CHKERRQ(ierr); 175 } 176 ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,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(pseudo);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 ierr = SNESSetJacobian(ts->snes,ts->Arhs,ts->B,SNESTSFormJacobian,ts);CHKERRQ(ierr); 297 PetscFunctionReturn(0); 298 } 299 /*------------------------------------------------------------*/ 300 301 #undef __FUNCT__ 302 #define __FUNCT__ "TSPseudoMonitorDefault" 303 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx) 304 { 305 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 306 PetscErrorCode ierr; 307 PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx; 308 309 PetscFunctionBegin; 310 if (!ctx) { 311 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 312 } 313 ierr = PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr); 314 if (!ctx) { 315 ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr); 316 } 317 PetscFunctionReturn(0); 318 } 319 320 #undef __FUNCT__ 321 #define __FUNCT__ "TSSetFromOptions_Pseudo" 322 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts) 323 { 324 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 325 PetscErrorCode ierr; 326 PetscTruth flg = PETSC_FALSE; 327 PetscViewerASCIIMonitor viewer; 328 329 PetscFunctionBegin; 330 ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr); 331 ierr = PetscOptionsTruth("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 332 if (flg) { 333 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 334 ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 335 } 336 flg = PETSC_FALSE; 337 ierr = PetscOptionsTruth("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 338 if (flg) { 339 ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr); 340 } 341 ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr); 342 ierr = PetscOptionsTail();CHKERRQ(ierr); 343 PetscFunctionReturn(0); 344 } 345 346 #undef __FUNCT__ 347 #define __FUNCT__ "TSView_Pseudo" 348 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer) 349 { 350 PetscFunctionBegin; 351 PetscFunctionReturn(0); 352 } 353 354 /* ----------------------------------------------------------------------------- */ 355 #undef __FUNCT__ 356 #define __FUNCT__ "TSPseudoSetVerifyTimeStep" 357 /*@C 358 TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 359 last timestep. 360 361 Collective on TS 362 363 Input Parameters: 364 + ts - timestep context 365 . dt - user-defined function to verify timestep 366 - ctx - [optional] user-defined context for private data 367 for the timestep verification routine (may be PETSC_NULL) 368 369 Level: advanced 370 371 Calling sequence of func: 372 . func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag); 373 374 . update - latest solution vector 375 . ctx - [optional] timestep context 376 . newdt - the timestep to use for the next step 377 . flag - flag indicating whether the last time step was acceptable 378 379 Notes: 380 The routine set here will be called by TSPseudoVerifyTimeStep() 381 during the timestepping process. 382 383 .keywords: timestep, pseudo, set, verify 384 385 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep() 386 @*/ 387 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx) 388 { 389 PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *); 390 391 PetscFunctionBegin; 392 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 393 394 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr); 395 if (f) { 396 ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr); 397 } 398 PetscFunctionReturn(0); 399 } 400 401 #undef __FUNCT__ 402 #define __FUNCT__ "TSPseudoSetTimeStepIncrement" 403 /*@ 404 TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to 405 dt when using the TSPseudoDefaultTimeStep() routine. 406 407 Collective on TS 408 409 Input Parameters: 410 + ts - the timestep context 411 - inc - the scaling factor >= 1.0 412 413 Options Database Key: 414 $ -ts_pseudo_increment <increment> 415 416 Level: advanced 417 418 .keywords: timestep, pseudo, set, increment 419 420 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 421 @*/ 422 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc) 423 { 424 PetscErrorCode ierr,(*f)(TS,PetscReal); 425 426 PetscFunctionBegin; 427 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 428 429 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)(void))&f);CHKERRQ(ierr); 430 if (f) { 431 ierr = (*f)(ts,inc);CHKERRQ(ierr); 432 } 433 PetscFunctionReturn(0); 434 } 435 436 #undef __FUNCT__ 437 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt" 438 /*@ 439 TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep 440 is computed via the formula 441 $ dt = initial_dt*initial_fnorm/current_fnorm 442 rather than the default update, 443 $ dt = current_dt*previous_fnorm/current_fnorm. 444 445 Collective on TS 446 447 Input Parameter: 448 . ts - the timestep context 449 450 Options Database Key: 451 $ -ts_pseudo_increment_dt_from_initial_dt 452 453 Level: advanced 454 455 .keywords: timestep, pseudo, set, increment 456 457 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 458 @*/ 459 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt(TS ts) 460 { 461 PetscErrorCode ierr,(*f)(TS); 462 463 PetscFunctionBegin; 464 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 465 466 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)(void))&f);CHKERRQ(ierr); 467 if (f) { 468 ierr = (*f)(ts);CHKERRQ(ierr); 469 } 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 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 PETSCTS_DLLEXPORT TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx) 505 { 506 PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *); 507 508 PetscFunctionBegin; 509 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 510 511 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr); 512 if (f) { 513 ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr); 514 } 515 PetscFunctionReturn(0); 516 } 517 518 /* ----------------------------------------------------------------------------- */ 519 520 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/ 521 EXTERN_C_BEGIN 522 #undef __FUNCT__ 523 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo" 524 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx) 525 { 526 TS_Pseudo *pseudo; 527 528 PetscFunctionBegin; 529 pseudo = (TS_Pseudo*)ts->data; 530 pseudo->verify = dt; 531 pseudo->verifyctx = ctx; 532 PetscFunctionReturn(0); 533 } 534 EXTERN_C_END 535 536 EXTERN_C_BEGIN 537 #undef __FUNCT__ 538 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 539 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 540 { 541 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 542 543 PetscFunctionBegin; 544 pseudo->dt_increment = inc; 545 PetscFunctionReturn(0); 546 } 547 EXTERN_C_END 548 549 EXTERN_C_BEGIN 550 #undef __FUNCT__ 551 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 552 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 553 { 554 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 555 556 PetscFunctionBegin; 557 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 558 PetscFunctionReturn(0); 559 } 560 EXTERN_C_END 561 562 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 563 EXTERN_C_BEGIN 564 #undef __FUNCT__ 565 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 566 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx) 567 { 568 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 569 570 PetscFunctionBegin; 571 pseudo->dt = dt; 572 pseudo->dtctx = ctx; 573 PetscFunctionReturn(0); 574 } 575 EXTERN_C_END 576 577 /* ----------------------------------------------------------------------------- */ 578 /*MC 579 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 580 581 This method solves equations of the form 582 583 $ F(X,Xdot) = 0 584 585 for steady state using the iteration 586 587 $ [G'] S = -F(X,0) 588 $ X += S 589 590 where 591 592 $ G(Y) = F(Y,(Y-X)/dt) 593 594 This is linearly-implicit Euler with the residual always evaluated "at steady 595 state". See note below. 596 597 Options database keys: 598 + -ts_pseudo_increment <real> - ratio of increase dt 599 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 600 601 Level: beginner 602 603 References: 604 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 605 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 606 607 Notes: 608 The residual computed by this method includes the transient term (Xdot is computed instead of 609 always being zero), but since the prediction from the last step is always the solution from the 610 last step, on the first Newton iteration we have 611 612 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 613 614 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 615 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 616 algorithm is no longer the one described in the referenced papers. 617 618 .seealso: TSCreate(), TS, TSSetType() 619 620 M*/ 621 EXTERN_C_BEGIN 622 #undef __FUNCT__ 623 #define __FUNCT__ "TSCreate_Pseudo" 624 PetscErrorCode PETSCTS_DLLEXPORT TSCreate_Pseudo(TS ts) 625 { 626 TS_Pseudo *pseudo; 627 PetscErrorCode ierr; 628 629 PetscFunctionBegin; 630 ts->ops->destroy = TSDestroy_Pseudo; 631 ts->ops->view = TSView_Pseudo; 632 633 if (ts->problem_type == TS_LINEAR) { 634 SETERRQ(PETSC_ERR_ARG_WRONG,"Only for nonlinear problems"); 635 } 636 if (!ts->Arhs) { 637 SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set Jacobian"); 638 } 639 640 ts->ops->setup = TSSetUp_Pseudo; 641 ts->ops->step = TSStep_Pseudo; 642 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 643 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 644 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 645 646 /* create the required nonlinear solver context */ 647 ierr = SNESCreate(((PetscObject)ts)->comm,&ts->snes);CHKERRQ(ierr); 648 ierr = PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);CHKERRQ(ierr); 649 650 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 651 ts->data = (void*)pseudo; 652 653 pseudo->dt_increment = 1.1; 654 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 655 pseudo->dt = TSPseudoDefaultTimeStep; 656 657 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C", 658 "TSPseudoSetVerifyTimeStep_Pseudo", 659 TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 660 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C", 661 "TSPseudoSetTimeStepIncrement_Pseudo", 662 TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 663 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C", 664 "TSPseudoIncrementDtFromInitialDt_Pseudo", 665 TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 666 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C", 667 "TSPseudoSetTimeStep_Pseudo", 668 TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 669 PetscFunctionReturn(0); 670 } 671 EXTERN_C_END 672 673 #undef __FUNCT__ 674 #define __FUNCT__ "TSPseudoDefaultTimeStep" 675 /*@C 676 TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping. 677 Use with TSPseudoSetTimeStep(). 678 679 Collective on TS 680 681 Input Parameters: 682 . ts - the timestep context 683 . dtctx - unused timestep context 684 685 Output Parameter: 686 . newdt - the timestep to use for the next step 687 688 Level: advanced 689 690 .keywords: timestep, pseudo, default 691 692 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 693 @*/ 694 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx) 695 { 696 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 697 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 698 PetscErrorCode ierr; 699 700 PetscFunctionBegin; 701 ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr); 702 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 703 if (pseudo->initial_fnorm == 0.0) { 704 /* first time through so compute initial function norm */ 705 pseudo->initial_fnorm = pseudo->fnorm; 706 fnorm_previous = pseudo->fnorm; 707 } 708 if (pseudo->fnorm == 0.0) { 709 *newdt = 1.e12*inc*ts->time_step; 710 } else if (pseudo->increment_dt_from_initial_dt) { 711 *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm; 712 } else { 713 *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 714 } 715 pseudo->fnorm_previous = pseudo->fnorm; 716 PetscFunctionReturn(0); 717 } 718