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