1 /* 2 Code for Timestepping with implicit backwards Euler. 3 */ 4 #include <private/tsimpl.h> /*I "petscts.h" I*/ 5 6 typedef struct { 7 Vec update; /* work vector where new solution is formed */ 8 Vec func; /* work vector where F(t[i],u[i]) is stored */ 9 Vec xdot; /* work vector for time derivative of state */ 10 11 /* information used for Pseudo-timestepping */ 12 13 PetscErrorCode (*dt)(TS,PetscReal*,void*); /* compute next timestep, and related context */ 14 void *dtctx; 15 PetscErrorCode (*verify)(TS,Vec,void*,PetscReal*,PetscBool *); /* verify previous timestep and related context */ 16 void *verifyctx; 17 18 PetscReal fnorm_initial,fnorm; /* original and current norm of F(u) */ 19 PetscReal fnorm_previous; 20 21 PetscReal dt_initial; /* initial time-step */ 22 PetscReal dt_increment; /* scaling that dt is incremented each time-step */ 23 PetscReal dt_max; /* maximum time step */ 24 PetscBool 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 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 TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscBool *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 TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscBool *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) 144 { 145 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 146 PetscInt its,lits,reject; 147 PetscBool stepok; 148 PetscReal next_time_step; 149 SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING; 150 PetscErrorCode ierr; 151 152 PetscFunctionBegin; 153 if (ts->steps == 0) { 154 pseudo->dt_initial = ts->time_step; 155 } 156 ierr = VecCopy(ts->vec_sol,pseudo->update);CHKERRQ(ierr); 157 next_time_step = ts->time_step; 158 ierr = TSPseudoComputeTimeStep(ts,&next_time_step);CHKERRQ(ierr); 159 for (reject=0; reject<ts->max_reject; reject++,ts->reject++) { 160 ts->time_step = next_time_step; 161 ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr); 162 ierr = SNESGetConvergedReason(ts->snes,&snesreason);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 = PetscInfo3(ts,"step=%D, nonlinear solve iterations=%D, linear solve iterations=%D\n",ts->steps,its,lits);CHKERRQ(ierr); 167 pseudo->fnorm = -1; /* The current norm is no longer valid, monitor must recompute it. */ 168 ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&next_time_step,&stepok);CHKERRQ(ierr); 169 if (stepok) break; 170 } 171 if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) { 172 ts->reason = TS_DIVERGED_NONLINEAR_SOLVE; 173 ierr = PetscInfo2(ts,"step=%D, nonlinear solve solve failures %D greater than current TS allowed, stopping solve\n",ts->steps,ts->num_snes_failures);CHKERRQ(ierr); 174 PetscFunctionReturn(0); 175 } 176 if (reject >= ts->max_reject) { 177 ts->reason = TS_DIVERGED_STEP_REJECTED; 178 ierr = PetscInfo2(ts,"step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);CHKERRQ(ierr); 179 PetscFunctionReturn(0); 180 } 181 ierr = VecCopy(pseudo->update,ts->vec_sol);CHKERRQ(ierr); 182 ts->ptime += ts->time_step; 183 ts->time_step = next_time_step; 184 ts->steps++; 185 PetscFunctionReturn(0); 186 } 187 188 /*------------------------------------------------------------*/ 189 #undef __FUNCT__ 190 #define __FUNCT__ "TSReset_Pseudo" 191 static PetscErrorCode TSReset_Pseudo(TS ts) 192 { 193 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 194 PetscErrorCode ierr; 195 196 PetscFunctionBegin; 197 ierr = VecDestroy(&pseudo->update);CHKERRQ(ierr); 198 ierr = VecDestroy(&pseudo->func);CHKERRQ(ierr); 199 ierr = VecDestroy(&pseudo->xdot);CHKERRQ(ierr); 200 PetscFunctionReturn(0); 201 } 202 203 #undef __FUNCT__ 204 #define __FUNCT__ "TSDestroy_Pseudo" 205 static PetscErrorCode TSDestroy_Pseudo(TS ts) 206 { 207 PetscErrorCode ierr; 208 209 PetscFunctionBegin; 210 ierr = TSReset_Pseudo(ts);CHKERRQ(ierr); 211 ierr = PetscFree(ts->data);CHKERRQ(ierr); 212 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C","",PETSC_NULL);CHKERRQ(ierr); 213 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C","",PETSC_NULL);CHKERRQ(ierr); 214 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetMaxTimeStep_C","",PETSC_NULL);CHKERRQ(ierr); 215 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C","",PETSC_NULL);CHKERRQ(ierr); 216 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C","",PETSC_NULL);CHKERRQ(ierr); 217 PetscFunctionReturn(0); 218 } 219 220 /*------------------------------------------------------------*/ 221 222 #undef __FUNCT__ 223 #define __FUNCT__ "TSPseudoGetXdot" 224 /* 225 Compute Xdot = (X^{n+1}-X^n)/dt) = 0 226 */ 227 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot) 228 { 229 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 230 const PetscScalar mdt = 1.0/ts->time_step,*xnp1,*xn; 231 PetscScalar *xdot; 232 PetscErrorCode ierr; 233 PetscInt i,n; 234 235 PetscFunctionBegin; 236 ierr = VecGetArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr); 237 ierr = VecGetArrayRead(X,&xnp1);CHKERRQ(ierr); 238 ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 239 ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr); 240 for (i=0; i<n; i++) { 241 xdot[i] = mdt*(xnp1[i] - xn[i]); 242 } 243 ierr = VecRestoreArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr); 244 ierr = VecRestoreArrayRead(X,&xnp1);CHKERRQ(ierr); 245 ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 246 *Xdot = pseudo->xdot; 247 PetscFunctionReturn(0); 248 } 249 250 #undef __FUNCT__ 251 #define __FUNCT__ "SNESTSFormFunction_Pseudo" 252 /* 253 The transient residual is 254 255 F(U^{n+1},(U^{n+1}-U^n)/dt) = 0 256 257 or for ODE, 258 259 (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0 260 261 This is the function that must be evaluated for transient simulation and for 262 finite difference Jacobians. On the first Newton step, this algorithm uses 263 a guess of U^{n+1} = U^n in which case the transient term vanishes and the 264 residual is actually the steady state residual. Pseudotransient 265 continuation as described in the literature is a linearly implicit 266 algorithm, it only takes this one Newton step with the steady state 267 residual, and then advances to the next time step. 268 */ 269 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts) 270 { 271 Vec Xdot; 272 PetscErrorCode ierr; 273 274 PetscFunctionBegin; 275 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 276 ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);CHKERRQ(ierr); 277 PetscFunctionReturn(0); 278 } 279 280 #undef __FUNCT__ 281 #define __FUNCT__ "SNESTSFormJacobian_Pseudo" 282 /* 283 This constructs the Jacobian needed for SNES. For DAE, this is 284 285 dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot 286 287 and for ODE: 288 289 J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs. 290 */ 291 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts) 292 { 293 Vec Xdot; 294 PetscErrorCode ierr; 295 296 PetscFunctionBegin; 297 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 298 ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,str,PETSC_FALSE);CHKERRQ(ierr); 299 PetscFunctionReturn(0); 300 } 301 302 303 #undef __FUNCT__ 304 #define __FUNCT__ "TSSetUp_Pseudo" 305 static PetscErrorCode TSSetUp_Pseudo(TS ts) 306 { 307 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 308 PetscErrorCode ierr; 309 310 PetscFunctionBegin; 311 ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr); 312 ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr); 313 ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr); 314 PetscFunctionReturn(0); 315 } 316 /*------------------------------------------------------------*/ 317 318 #undef __FUNCT__ 319 #define __FUNCT__ "TSPseudoMonitorDefault" 320 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *dummy) 321 { 322 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 323 PetscErrorCode ierr; 324 PetscViewer viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)ts)->comm); 325 326 PetscFunctionBegin; 327 if (pseudo->fnorm < 0) { /* The last computed norm is stale, recompute */ 328 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 329 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr); 330 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 331 } 332 ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr); 333 ierr = PetscViewerASCIIPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr); 334 ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr); 335 PetscFunctionReturn(0); 336 } 337 338 #undef __FUNCT__ 339 #define __FUNCT__ "TSSetFromOptions_Pseudo" 340 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts) 341 { 342 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 343 PetscErrorCode ierr; 344 PetscBool flg = PETSC_FALSE; 345 PetscViewer viewer; 346 347 PetscFunctionBegin; 348 ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr); 349 ierr = PetscOptionsBool("-ts_monitor_pseudo","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 350 if (flg) { 351 ierr = PetscViewerASCIIOpen(((PetscObject)ts)->comm,"stdout",&viewer);CHKERRQ(ierr); 352 ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr); 353 } 354 flg = PETSC_FALSE; 355 ierr = PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 356 if (flg) { 357 ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr); 358 } 359 ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr); 360 ierr = PetscOptionsReal("-ts_pseudo_max_dt","Maximum value for dt","TSPseudoSetMaxTimeStep",pseudo->dt_max,&pseudo->dt_max,0);CHKERRQ(ierr); 361 362 ierr = SNESSetFromOptions(ts->snes);CHKERRQ(ierr); 363 ierr = PetscOptionsTail();CHKERRQ(ierr); 364 PetscFunctionReturn(0); 365 } 366 367 #undef __FUNCT__ 368 #define __FUNCT__ "TSView_Pseudo" 369 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer) 370 { 371 PetscErrorCode ierr; 372 373 PetscFunctionBegin; 374 ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr); 375 PetscFunctionReturn(0); 376 } 377 378 /* ----------------------------------------------------------------------------- */ 379 #undef __FUNCT__ 380 #define __FUNCT__ "TSPseudoSetVerifyTimeStep" 381 /*@C 382 TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 383 last timestep. 384 385 Logically Collective on TS 386 387 Input Parameters: 388 + ts - timestep context 389 . dt - user-defined function to verify timestep 390 - ctx - [optional] user-defined context for private data 391 for the timestep verification routine (may be PETSC_NULL) 392 393 Level: advanced 394 395 Calling sequence of func: 396 . func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscBool *flag); 397 398 . update - latest solution vector 399 . ctx - [optional] timestep context 400 . newdt - the timestep to use for the next step 401 . flag - flag indicating whether the last time step was acceptable 402 403 Notes: 404 The routine set here will be called by TSPseudoVerifyTimeStep() 405 during the timestepping process. 406 407 .keywords: timestep, pseudo, set, verify 408 409 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep() 410 @*/ 411 PetscErrorCode TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscBool *),void* ctx) 412 { 413 PetscErrorCode ierr; 414 415 PetscFunctionBegin; 416 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 417 ierr = PetscTryMethod(ts,"TSPseudoSetVerifyTimeStep_C",(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscBool *),void *),(ts,dt,ctx));CHKERRQ(ierr); 418 PetscFunctionReturn(0); 419 } 420 421 #undef __FUNCT__ 422 #define __FUNCT__ "TSPseudoSetTimeStepIncrement" 423 /*@ 424 TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to 425 dt when using the TSPseudoDefaultTimeStep() routine. 426 427 Logically Collective on TS 428 429 Input Parameters: 430 + ts - the timestep context 431 - inc - the scaling factor >= 1.0 432 433 Options Database Key: 434 $ -ts_pseudo_increment <increment> 435 436 Level: advanced 437 438 .keywords: timestep, pseudo, set, increment 439 440 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 441 @*/ 442 PetscErrorCode TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc) 443 { 444 PetscErrorCode ierr; 445 446 PetscFunctionBegin; 447 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 448 PetscValidLogicalCollectiveReal(ts,inc,2); 449 ierr = PetscTryMethod(ts,"TSPseudoSetTimeStepIncrement_C",(TS,PetscReal),(ts,inc));CHKERRQ(ierr); 450 PetscFunctionReturn(0); 451 } 452 453 #undef __FUNCT__ 454 #define __FUNCT__ "TSPseudoSetMaxTimeStep" 455 /*@ 456 TSPseudoSetMaxTimeStep - Sets the maximum time step 457 when using the TSPseudoDefaultTimeStep() routine. 458 459 Logically Collective on TS 460 461 Input Parameters: 462 + ts - the timestep context 463 - maxdt - the maximum time step, use a non-positive value to deactivate 464 465 Options Database Key: 466 $ -ts_pseudo_max_dt <increment> 467 468 Level: advanced 469 470 .keywords: timestep, pseudo, set 471 472 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 473 @*/ 474 PetscErrorCode TSPseudoSetMaxTimeStep(TS ts,PetscReal maxdt) 475 { 476 PetscErrorCode ierr; 477 478 PetscFunctionBegin; 479 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 480 PetscValidLogicalCollectiveReal(ts,maxdt,2); 481 ierr = PetscTryMethod(ts,"TSPseudoSetMaxTimeStep_C",(TS,PetscReal),(ts,maxdt));CHKERRQ(ierr); 482 PetscFunctionReturn(0); 483 } 484 485 #undef __FUNCT__ 486 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt" 487 /*@ 488 TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep 489 is computed via the formula 490 $ dt = initial_dt*initial_fnorm/current_fnorm 491 rather than the default update, 492 $ dt = current_dt*previous_fnorm/current_fnorm. 493 494 Logically Collective on TS 495 496 Input Parameter: 497 . ts - the timestep context 498 499 Options Database Key: 500 $ -ts_pseudo_increment_dt_from_initial_dt 501 502 Level: advanced 503 504 .keywords: timestep, pseudo, set, increment 505 506 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 507 @*/ 508 PetscErrorCode TSPseudoIncrementDtFromInitialDt(TS ts) 509 { 510 PetscErrorCode ierr; 511 512 PetscFunctionBegin; 513 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 514 ierr = PetscTryMethod(ts,"TSPseudoIncrementDtFromInitialDt_C",(TS),(ts));CHKERRQ(ierr); 515 PetscFunctionReturn(0); 516 } 517 518 519 #undef __FUNCT__ 520 #define __FUNCT__ "TSPseudoSetTimeStep" 521 /*@C 522 TSPseudoSetTimeStep - Sets the user-defined routine to be 523 called at each pseudo-timestep to update the timestep. 524 525 Logically Collective on TS 526 527 Input Parameters: 528 + ts - timestep context 529 . dt - function to compute timestep 530 - ctx - [optional] user-defined context for private data 531 required by the function (may be PETSC_NULL) 532 533 Level: intermediate 534 535 Calling sequence of func: 536 . func (TS ts,PetscReal *newdt,void *ctx); 537 538 . newdt - the newly computed timestep 539 . ctx - [optional] timestep context 540 541 Notes: 542 The routine set here will be called by TSPseudoComputeTimeStep() 543 during the timestepping process. 544 545 .keywords: timestep, pseudo, set 546 547 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep() 548 @*/ 549 PetscErrorCode TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx) 550 { 551 PetscErrorCode ierr; 552 553 PetscFunctionBegin; 554 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 555 ierr = PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *),(ts,dt,ctx));CHKERRQ(ierr); 556 PetscFunctionReturn(0); 557 } 558 559 /* ----------------------------------------------------------------------------- */ 560 561 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool *); /* force argument to next function to not be extern C*/ 562 EXTERN_C_BEGIN 563 #undef __FUNCT__ 564 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo" 565 PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx) 566 { 567 TS_Pseudo *pseudo; 568 569 PetscFunctionBegin; 570 pseudo = (TS_Pseudo*)ts->data; 571 pseudo->verify = dt; 572 pseudo->verifyctx = ctx; 573 PetscFunctionReturn(0); 574 } 575 EXTERN_C_END 576 577 EXTERN_C_BEGIN 578 #undef __FUNCT__ 579 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 580 PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 581 { 582 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 583 584 PetscFunctionBegin; 585 pseudo->dt_increment = inc; 586 PetscFunctionReturn(0); 587 } 588 EXTERN_C_END 589 590 EXTERN_C_BEGIN 591 #undef __FUNCT__ 592 #define __FUNCT__ "TSPseudoSetMaxTimeStep_Pseudo" 593 PetscErrorCode TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt) 594 { 595 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 596 597 PetscFunctionBegin; 598 pseudo->dt_max = maxdt; 599 PetscFunctionReturn(0); 600 } 601 EXTERN_C_END 602 603 EXTERN_C_BEGIN 604 #undef __FUNCT__ 605 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 606 PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 607 { 608 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 609 610 PetscFunctionBegin; 611 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 612 PetscFunctionReturn(0); 613 } 614 EXTERN_C_END 615 616 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 617 EXTERN_C_BEGIN 618 #undef __FUNCT__ 619 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 620 PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx) 621 { 622 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 623 624 PetscFunctionBegin; 625 pseudo->dt = dt; 626 pseudo->dtctx = ctx; 627 PetscFunctionReturn(0); 628 } 629 EXTERN_C_END 630 631 /* ----------------------------------------------------------------------------- */ 632 /*MC 633 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 634 635 This method solves equations of the form 636 637 $ F(X,Xdot) = 0 638 639 for steady state using the iteration 640 641 $ [G'] S = -F(X,0) 642 $ X += S 643 644 where 645 646 $ G(Y) = F(Y,(Y-X)/dt) 647 648 This is linearly-implicit Euler with the residual always evaluated "at steady 649 state". See note below. 650 651 Options database keys: 652 + -ts_pseudo_increment <real> - ratio of increase dt 653 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 654 655 Level: beginner 656 657 References: 658 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 659 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 660 661 Notes: 662 The residual computed by this method includes the transient term (Xdot is computed instead of 663 always being zero), but since the prediction from the last step is always the solution from the 664 last step, on the first Newton iteration we have 665 666 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 667 668 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 669 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 670 algorithm is no longer the one described in the referenced papers. 671 672 .seealso: TSCreate(), TS, TSSetType() 673 674 M*/ 675 EXTERN_C_BEGIN 676 #undef __FUNCT__ 677 #define __FUNCT__ "TSCreate_Pseudo" 678 PetscErrorCode TSCreate_Pseudo(TS ts) 679 { 680 TS_Pseudo *pseudo; 681 PetscErrorCode ierr; 682 SNES snes; 683 const SNESType stype; 684 685 PetscFunctionBegin; 686 ts->ops->reset = TSReset_Pseudo; 687 ts->ops->destroy = TSDestroy_Pseudo; 688 ts->ops->view = TSView_Pseudo; 689 690 ts->ops->setup = TSSetUp_Pseudo; 691 ts->ops->step = TSStep_Pseudo; 692 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 693 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 694 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 695 696 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 697 ierr = SNESGetType(snes,&stype);CHKERRQ(ierr); 698 if (!stype) {ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);} 699 700 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 701 ts->data = (void*)pseudo; 702 703 pseudo->dt_increment = 1.1; 704 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 705 pseudo->dt = TSPseudoDefaultTimeStep; 706 pseudo->fnorm = -1; 707 708 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C", 709 "TSPseudoSetVerifyTimeStep_Pseudo", 710 TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 711 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C", 712 "TSPseudoSetTimeStepIncrement_Pseudo", 713 TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 714 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetMaxTimeStep_C", 715 "TSPseudoSetMaxTimeStep_Pseudo", 716 TSPseudoSetMaxTimeStep_Pseudo);CHKERRQ(ierr); 717 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C", 718 "TSPseudoIncrementDtFromInitialDt_Pseudo", 719 TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 720 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C", 721 "TSPseudoSetTimeStep_Pseudo", 722 TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 723 PetscFunctionReturn(0); 724 } 725 EXTERN_C_END 726 727 #undef __FUNCT__ 728 #define __FUNCT__ "TSPseudoDefaultTimeStep" 729 /*@C 730 TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping. 731 Use with TSPseudoSetTimeStep(). 732 733 Collective on TS 734 735 Input Parameters: 736 . ts - the timestep context 737 . dtctx - unused timestep context 738 739 Output Parameter: 740 . newdt - the timestep to use for the next step 741 742 Level: advanced 743 744 .keywords: timestep, pseudo, default 745 746 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 747 @*/ 748 PetscErrorCode TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx) 749 { 750 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 751 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 752 PetscErrorCode ierr; 753 754 PetscFunctionBegin; 755 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 756 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr); 757 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 758 if (pseudo->fnorm_initial == 0.0) { 759 /* first time through so compute initial function norm */ 760 pseudo->fnorm_initial = pseudo->fnorm; 761 fnorm_previous = pseudo->fnorm; 762 } 763 if (pseudo->fnorm == 0.0) { 764 *newdt = 1.e12*inc*ts->time_step; 765 } else if (pseudo->increment_dt_from_initial_dt) { 766 *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm; 767 } else { 768 *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 769 } 770 if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max); 771 pseudo->fnorm_previous = pseudo->fnorm; 772 PetscFunctionReturn(0); 773 } 774