1 /* 2 Code for Timestepping with implicit backwards Euler. 3 */ 4 #include <petsc-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 PetscFunctionReturn(0); 136 } 137 138 /* --------------------------------------------------------------------------------*/ 139 140 #undef __FUNCT__ 141 #define __FUNCT__ "TSStep_Pseudo" 142 static PetscErrorCode TSStep_Pseudo(TS ts) 143 { 144 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 145 PetscInt its,lits,reject; 146 PetscBool stepok; 147 PetscReal next_time_step; 148 SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING; 149 PetscErrorCode ierr; 150 151 PetscFunctionBegin; 152 if (ts->steps == 0) pseudo->dt_initial = ts->time_step; 153 ierr = VecCopy(ts->vec_sol,pseudo->update);CHKERRQ(ierr); 154 next_time_step = ts->time_step; 155 ierr = TSPseudoComputeTimeStep(ts,&next_time_step);CHKERRQ(ierr); 156 for (reject=0; reject<ts->max_reject; reject++,ts->reject++) { 157 ts->time_step = next_time_step; 158 ierr = TSPreStep(ts);CHKERRQ(ierr); 159 ierr = TSPreStage(ts,ts->ptime+ts->time_step);CHKERRQ(ierr); 160 ierr = SNESSolve(ts->snes,NULL,pseudo->update);CHKERRQ(ierr); 161 ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr); 162 ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr); 163 ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr); 164 ts->snes_its += its; ts->ksp_its += lits; 165 ierr = PetscInfo3(ts,"step=%D, nonlinear solve iterations=%D, linear solve iterations=%D\n",ts->steps,its,lits);CHKERRQ(ierr); 166 pseudo->fnorm = -1; /* The current norm is no longer valid, monitor must recompute it. */ 167 ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&next_time_step,&stepok);CHKERRQ(ierr); 168 if (stepok) break; 169 } 170 if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) { 171 ts->reason = TS_DIVERGED_NONLINEAR_SOLVE; 172 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); 173 PetscFunctionReturn(0); 174 } 175 if (reject >= ts->max_reject) { 176 ts->reason = TS_DIVERGED_STEP_REJECTED; 177 ierr = PetscInfo2(ts,"step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);CHKERRQ(ierr); 178 PetscFunctionReturn(0); 179 } 180 ierr = VecCopy(pseudo->update,ts->vec_sol);CHKERRQ(ierr); 181 ts->ptime += ts->time_step; 182 ts->time_step = next_time_step; 183 ts->steps++; 184 PetscFunctionReturn(0); 185 } 186 187 /*------------------------------------------------------------*/ 188 #undef __FUNCT__ 189 #define __FUNCT__ "TSReset_Pseudo" 190 static PetscErrorCode TSReset_Pseudo(TS ts) 191 { 192 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 193 PetscErrorCode ierr; 194 195 PetscFunctionBegin; 196 ierr = VecDestroy(&pseudo->update);CHKERRQ(ierr); 197 ierr = VecDestroy(&pseudo->func);CHKERRQ(ierr); 198 ierr = VecDestroy(&pseudo->xdot);CHKERRQ(ierr); 199 PetscFunctionReturn(0); 200 } 201 202 #undef __FUNCT__ 203 #define __FUNCT__ "TSDestroy_Pseudo" 204 static PetscErrorCode TSDestroy_Pseudo(TS ts) 205 { 206 PetscErrorCode ierr; 207 208 PetscFunctionBegin; 209 ierr = TSReset_Pseudo(ts);CHKERRQ(ierr); 210 ierr = PetscFree(ts->data);CHKERRQ(ierr); 211 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C","",NULL);CHKERRQ(ierr); 212 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C","",NULL);CHKERRQ(ierr); 213 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C","",NULL);CHKERRQ(ierr); 214 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C","",NULL);CHKERRQ(ierr); 215 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C","",NULL);CHKERRQ(ierr); 216 PetscFunctionReturn(0); 217 } 218 219 /*------------------------------------------------------------*/ 220 221 #undef __FUNCT__ 222 #define __FUNCT__ "TSPseudoGetXdot" 223 /* 224 Compute Xdot = (X^{n+1}-X^n)/dt) = 0 225 */ 226 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot) 227 { 228 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 229 const PetscScalar mdt = 1.0/ts->time_step,*xnp1,*xn; 230 PetscScalar *xdot; 231 PetscErrorCode ierr; 232 PetscInt i,n; 233 234 PetscFunctionBegin; 235 ierr = VecGetArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr); 236 ierr = VecGetArrayRead(X,&xnp1);CHKERRQ(ierr); 237 ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 238 ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr); 239 for (i=0; i<n; i++) xdot[i] = mdt*(xnp1[i] - xn[i]); 240 ierr = VecRestoreArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr); 241 ierr = VecRestoreArrayRead(X,&xnp1);CHKERRQ(ierr); 242 ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 243 *Xdot = pseudo->xdot; 244 PetscFunctionReturn(0); 245 } 246 247 #undef __FUNCT__ 248 #define __FUNCT__ "SNESTSFormFunction_Pseudo" 249 /* 250 The transient residual is 251 252 F(U^{n+1},(U^{n+1}-U^n)/dt) = 0 253 254 or for ODE, 255 256 (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0 257 258 This is the function that must be evaluated for transient simulation and for 259 finite difference Jacobians. On the first Newton step, this algorithm uses 260 a guess of U^{n+1} = U^n in which case the transient term vanishes and the 261 residual is actually the steady state residual. Pseudotransient 262 continuation as described in the literature is a linearly implicit 263 algorithm, it only takes this one Newton step with the steady state 264 residual, and then advances to the next time step. 265 */ 266 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts) 267 { 268 Vec Xdot; 269 PetscErrorCode ierr; 270 271 PetscFunctionBegin; 272 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 273 ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);CHKERRQ(ierr); 274 PetscFunctionReturn(0); 275 } 276 277 #undef __FUNCT__ 278 #define __FUNCT__ "SNESTSFormJacobian_Pseudo" 279 /* 280 This constructs the Jacobian needed for SNES. For DAE, this is 281 282 dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot 283 284 and for ODE: 285 286 J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs. 287 */ 288 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts) 289 { 290 Vec Xdot; 291 PetscErrorCode ierr; 292 293 PetscFunctionBegin; 294 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 295 ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,str,PETSC_FALSE);CHKERRQ(ierr); 296 PetscFunctionReturn(0); 297 } 298 299 300 #undef __FUNCT__ 301 #define __FUNCT__ "TSSetUp_Pseudo" 302 static PetscErrorCode TSSetUp_Pseudo(TS ts) 303 { 304 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 305 PetscErrorCode ierr; 306 307 PetscFunctionBegin; 308 ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr); 309 ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr); 310 ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr); 311 PetscFunctionReturn(0); 312 } 313 /*------------------------------------------------------------*/ 314 315 #undef __FUNCT__ 316 #define __FUNCT__ "TSPseudoMonitorDefault" 317 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *dummy) 318 { 319 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 320 PetscErrorCode ierr; 321 PetscViewer viewer = (PetscViewer) dummy; 322 323 PetscFunctionBegin; 324 if (!viewer) { 325 ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)ts),&viewer);CHKERRQ(ierr); 326 } 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,NULL);CHKERRQ(ierr); 350 if (flg) { 351 ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ts),"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,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 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 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 #undef __FUNCT__ 563 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo" 564 PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void *ctx) 565 { 566 TS_Pseudo *pseudo; 567 568 PetscFunctionBegin; 569 pseudo = (TS_Pseudo*)ts->data; 570 pseudo->verify = dt; 571 pseudo->verifyctx = ctx; 572 PetscFunctionReturn(0); 573 } 574 575 #undef __FUNCT__ 576 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 577 PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 578 { 579 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 580 581 PetscFunctionBegin; 582 pseudo->dt_increment = inc; 583 PetscFunctionReturn(0); 584 } 585 586 #undef __FUNCT__ 587 #define __FUNCT__ "TSPseudoSetMaxTimeStep_Pseudo" 588 PetscErrorCode TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt) 589 { 590 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 591 592 PetscFunctionBegin; 593 pseudo->dt_max = maxdt; 594 PetscFunctionReturn(0); 595 } 596 597 #undef __FUNCT__ 598 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 599 PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 600 { 601 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 602 603 PetscFunctionBegin; 604 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 605 PetscFunctionReturn(0); 606 } 607 608 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 609 #undef __FUNCT__ 610 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 611 PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void *ctx) 612 { 613 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 614 615 PetscFunctionBegin; 616 pseudo->dt = dt; 617 pseudo->dtctx = ctx; 618 PetscFunctionReturn(0); 619 } 620 621 /* ----------------------------------------------------------------------------- */ 622 /*MC 623 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 624 625 This method solves equations of the form 626 627 $ F(X,Xdot) = 0 628 629 for steady state using the iteration 630 631 $ [G'] S = -F(X,0) 632 $ X += S 633 634 where 635 636 $ G(Y) = F(Y,(Y-X)/dt) 637 638 This is linearly-implicit Euler with the residual always evaluated "at steady 639 state". See note below. 640 641 Options database keys: 642 + -ts_pseudo_increment <real> - ratio of increase dt 643 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 644 645 Level: beginner 646 647 References: 648 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 649 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 650 651 Notes: 652 The residual computed by this method includes the transient term (Xdot is computed instead of 653 always being zero), but since the prediction from the last step is always the solution from the 654 last step, on the first Newton iteration we have 655 656 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 657 658 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 659 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 660 algorithm is no longer the one described in the referenced papers. 661 662 .seealso: TSCreate(), TS, TSSetType() 663 664 M*/ 665 #undef __FUNCT__ 666 #define __FUNCT__ "TSCreate_Pseudo" 667 PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts) 668 { 669 TS_Pseudo *pseudo; 670 PetscErrorCode ierr; 671 SNES snes; 672 SNESType stype; 673 674 PetscFunctionBegin; 675 ts->ops->reset = TSReset_Pseudo; 676 ts->ops->destroy = TSDestroy_Pseudo; 677 ts->ops->view = TSView_Pseudo; 678 679 ts->ops->setup = TSSetUp_Pseudo; 680 ts->ops->step = TSStep_Pseudo; 681 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 682 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 683 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 684 685 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 686 ierr = SNESGetType(snes,&stype);CHKERRQ(ierr); 687 if (!stype) {ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);} 688 689 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 690 ts->data = (void*)pseudo; 691 692 pseudo->dt_increment = 1.1; 693 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 694 pseudo->dt = TSPseudoDefaultTimeStep; 695 pseudo->fnorm = -1; 696 697 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C","TSPseudoSetVerifyTimeStep_Pseudo",TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 698 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C","TSPseudoSetTimeStepIncrement_Pseudo",TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 699 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C","TSPseudoSetMaxTimeStep_Pseudo",TSPseudoSetMaxTimeStep_Pseudo);CHKERRQ(ierr); 700 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C","TSPseudoIncrementDtFromInitialDt_Pseudo",TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 701 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C","TSPseudoSetTimeStep_Pseudo",TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 702 PetscFunctionReturn(0); 703 } 704 705 #undef __FUNCT__ 706 #define __FUNCT__ "TSPseudoDefaultTimeStep" 707 /*@C 708 TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping. 709 Use with TSPseudoSetTimeStep(). 710 711 Collective on TS 712 713 Input Parameters: 714 . ts - the timestep context 715 . dtctx - unused timestep context 716 717 Output Parameter: 718 . newdt - the timestep to use for the next step 719 720 Level: advanced 721 722 .keywords: timestep, pseudo, default 723 724 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 725 @*/ 726 PetscErrorCode TSPseudoDefaultTimeStep(TS ts,PetscReal *newdt,void *dtctx) 727 { 728 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 729 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 730 PetscErrorCode ierr; 731 732 PetscFunctionBegin; 733 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 734 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr); 735 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 736 if (pseudo->fnorm_initial == 0.0) { 737 /* first time through so compute initial function norm */ 738 pseudo->fnorm_initial = pseudo->fnorm; 739 fnorm_previous = pseudo->fnorm; 740 } 741 if (pseudo->fnorm == 0.0) *newdt = 1.e12*inc*ts->time_step; 742 else if (pseudo->increment_dt_from_initial_dt) *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm; 743 else *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 744 if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max); 745 pseudo->fnorm_previous = pseudo->fnorm; 746 PetscFunctionReturn(0); 747 } 748