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 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: TSPseudoVerifyTimeStepDefault(), 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 TSPseudoTimeStepDefault() 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(), TSPseudoTimeStepDefault() 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 TSPseudoTimeStepDefault() 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(), TSPseudoTimeStepDefault() 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(), TSPseudoTimeStepDefault() 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 If not set then TSPseudoTimeStepDefault() is automatically used 545 546 .keywords: timestep, pseudo, set 547 548 .seealso: TSPseudoTimeStepDefault(), TSPseudoComputeTimeStep() 549 @*/ 550 PetscErrorCode TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void *ctx) 551 { 552 PetscErrorCode ierr; 553 554 PetscFunctionBegin; 555 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 556 ierr = PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal*,void*),void*),(ts,dt,ctx));CHKERRQ(ierr); 557 PetscFunctionReturn(0); 558 } 559 560 /* ----------------------------------------------------------------------------- */ 561 562 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool*); /* force argument to next function to not be extern C*/ 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 576 #undef __FUNCT__ 577 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 578 PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 579 { 580 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 581 582 PetscFunctionBegin; 583 pseudo->dt_increment = inc; 584 PetscFunctionReturn(0); 585 } 586 587 #undef __FUNCT__ 588 #define __FUNCT__ "TSPseudoSetMaxTimeStep_Pseudo" 589 PetscErrorCode TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt) 590 { 591 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 592 593 PetscFunctionBegin; 594 pseudo->dt_max = maxdt; 595 PetscFunctionReturn(0); 596 } 597 598 #undef __FUNCT__ 599 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 600 PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 601 { 602 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 603 604 PetscFunctionBegin; 605 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 606 PetscFunctionReturn(0); 607 } 608 609 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 610 #undef __FUNCT__ 611 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 612 PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void *ctx) 613 { 614 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 615 616 PetscFunctionBegin; 617 pseudo->dt = dt; 618 pseudo->dtctx = ctx; 619 PetscFunctionReturn(0); 620 } 621 622 /* ----------------------------------------------------------------------------- */ 623 /*MC 624 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 625 626 This method solves equations of the form 627 628 $ F(X,Xdot) = 0 629 630 for steady state using the iteration 631 632 $ [G'] S = -F(X,0) 633 $ X += S 634 635 where 636 637 $ G(Y) = F(Y,(Y-X)/dt) 638 639 This is linearly-implicit Euler with the residual always evaluated "at steady 640 state". See note below. 641 642 Options database keys: 643 + -ts_pseudo_increment <real> - ratio of increase dt 644 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 645 646 Level: beginner 647 648 References: 649 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 650 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 651 652 Notes: 653 The residual computed by this method includes the transient term (Xdot is computed instead of 654 always being zero), but since the prediction from the last step is always the solution from the 655 last step, on the first Newton iteration we have 656 657 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 658 659 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 660 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 661 algorithm is no longer the one described in the referenced papers. 662 663 .seealso: TSCreate(), TS, TSSetType() 664 665 M*/ 666 #undef __FUNCT__ 667 #define __FUNCT__ "TSCreate_Pseudo" 668 PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts) 669 { 670 TS_Pseudo *pseudo; 671 PetscErrorCode ierr; 672 SNES snes; 673 SNESType stype; 674 675 PetscFunctionBegin; 676 ts->ops->reset = TSReset_Pseudo; 677 ts->ops->destroy = TSDestroy_Pseudo; 678 ts->ops->view = TSView_Pseudo; 679 680 ts->ops->setup = TSSetUp_Pseudo; 681 ts->ops->step = TSStep_Pseudo; 682 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 683 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 684 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 685 686 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 687 ierr = SNESGetType(snes,&stype);CHKERRQ(ierr); 688 if (!stype) {ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);} 689 690 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 691 ts->data = (void*)pseudo; 692 693 pseudo->dt_increment = 1.1; 694 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 695 pseudo->dt = TSPseudoTimeStepDefault; 696 pseudo->fnorm = -1; 697 698 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 699 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 700 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",TSPseudoSetMaxTimeStep_Pseudo);CHKERRQ(ierr); 701 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 702 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 703 PetscFunctionReturn(0); 704 } 705 706 #undef __FUNCT__ 707 #define __FUNCT__ "TSPseudoTimeStepDefault" 708 /*@C 709 TSPseudoTimeStepDefault - Default code to compute pseudo-timestepping. 710 Use with TSPseudoSetTimeStep(). 711 712 Collective on TS 713 714 Input Parameters: 715 . ts - the timestep context 716 . dtctx - unused timestep context 717 718 Output Parameter: 719 . newdt - the timestep to use for the next step 720 721 Level: advanced 722 723 .keywords: timestep, pseudo, default 724 725 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 726 @*/ 727 PetscErrorCode TSPseudoTimeStepDefault(TS ts,PetscReal *newdt,void *dtctx) 728 { 729 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 730 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 731 PetscErrorCode ierr; 732 733 PetscFunctionBegin; 734 ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr); 735 ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr); 736 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 737 if (pseudo->fnorm_initial == 0.0) { 738 /* first time through so compute initial function norm */ 739 pseudo->fnorm_initial = pseudo->fnorm; 740 fnorm_previous = pseudo->fnorm; 741 } 742 if (pseudo->fnorm == 0.0) *newdt = 1.e12*inc*ts->time_step; 743 else if (pseudo->increment_dt_from_initial_dt) *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm; 744 else *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 745 if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max); 746 pseudo->fnorm_previous = pseudo->fnorm; 747 PetscFunctionReturn(0); 748 } 749