1 #define PETSCTS_DLL 2 3 /* 4 Code for Timestepping with implicit backwards Euler. 5 */ 6 #include "private/tsimpl.h" /*I "petscts.h" I*/ 7 8 typedef struct { 9 Vec update; /* work vector where new solution is formed */ 10 Vec func; /* work vector where F(t[i],u[i]) is stored */ 11 Vec xdot; /* work vector for time derivative of state */ 12 13 /* information used for Pseudo-timestepping */ 14 15 PetscErrorCode (*dt)(TS,PetscReal*,void*); /* compute next timestep, and related context */ 16 void *dtctx; 17 PetscErrorCode (*verify)(TS,Vec,void*,PetscReal*,PetscTruth*); /* verify previous timestep and related context */ 18 void *verifyctx; 19 20 PetscReal initial_fnorm,fnorm; /* original and current norm of F(u) */ 21 PetscReal fnorm_previous; 22 23 PetscReal dt_increment; /* scaling that dt is incremented each time-step */ 24 PetscTruth increment_dt_from_initial_dt; 25 } TS_Pseudo; 26 27 /* ------------------------------------------------------------------------------*/ 28 29 #undef __FUNCT__ 30 #define __FUNCT__ "TSPseudoComputeTimeStep" 31 /*@ 32 TSPseudoComputeTimeStep - Computes the next timestep for a currently running 33 pseudo-timestepping process. 34 35 Collective on TS 36 37 Input Parameter: 38 . ts - timestep context 39 40 Output Parameter: 41 . dt - newly computed timestep 42 43 Level: advanced 44 45 Notes: 46 The routine to be called here to compute the timestep should be 47 set by calling TSPseudoSetTimeStep(). 48 49 .keywords: timestep, pseudo, compute 50 51 .seealso: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep() 52 @*/ 53 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoComputeTimeStep(TS ts,PetscReal *dt) 54 { 55 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 56 PetscErrorCode ierr; 57 58 PetscFunctionBegin; 59 ierr = PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 60 ierr = (*pseudo->dt)(ts,dt,pseudo->dtctx);CHKERRQ(ierr); 61 ierr = PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr); 62 PetscFunctionReturn(0); 63 } 64 65 66 /* ------------------------------------------------------------------------------*/ 67 #undef __FUNCT__ 68 #define __FUNCT__ "TSPseudoDefaultVerifyTimeStep" 69 /*@C 70 TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep. 71 72 Collective on TS 73 74 Input Parameters: 75 + ts - the timestep context 76 . dtctx - unused timestep context 77 - update - latest solution vector 78 79 Output Parameters: 80 + newdt - the timestep to use for the next step 81 - flag - flag indicating whether the last time step was acceptable 82 83 Level: advanced 84 85 Note: 86 This routine always returns a flag of 1, indicating an acceptable 87 timestep. 88 89 .keywords: timestep, pseudo, default, verify 90 91 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep() 92 @*/ 93 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscTruth *flag) 94 { 95 PetscFunctionBegin; 96 *flag = PETSC_TRUE; 97 PetscFunctionReturn(0); 98 } 99 100 101 #undef __FUNCT__ 102 #define __FUNCT__ "TSPseudoVerifyTimeStep" 103 /*@ 104 TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable. 105 106 Collective on TS 107 108 Input Parameters: 109 + ts - timestep context 110 - update - latest solution vector 111 112 Output Parameters: 113 + dt - newly computed timestep (if it had to shrink) 114 - flag - indicates if current timestep was ok 115 116 Level: advanced 117 118 Notes: 119 The routine to be called here to compute the timestep should be 120 set by calling TSPseudoSetVerifyTimeStep(). 121 122 .keywords: timestep, pseudo, verify 123 124 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep() 125 @*/ 126 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscTruth *flag) 127 { 128 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 129 PetscErrorCode ierr; 130 131 PetscFunctionBegin; 132 if (!pseudo->verify) {*flag = PETSC_TRUE; PetscFunctionReturn(0);} 133 134 ierr = (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);CHKERRQ(ierr); 135 136 PetscFunctionReturn(0); 137 } 138 139 /* --------------------------------------------------------------------------------*/ 140 141 #undef __FUNCT__ 142 #define __FUNCT__ "TSStep_Pseudo" 143 static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime) 144 { 145 Vec sol = ts->vec_sol; 146 PetscErrorCode ierr; 147 PetscInt i,max_steps = ts->max_steps,its,lits; 148 PetscTruth ok; 149 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 150 PetscReal current_time_step; 151 152 PetscFunctionBegin; 153 *steps = -ts->steps; 154 155 ierr = VecCopy(sol,pseudo->update);CHKERRQ(ierr); 156 for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) { 157 ierr = TSPseudoComputeTimeStep(ts,&ts->time_step);CHKERRQ(ierr); 158 ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr); 159 current_time_step = ts->time_step; 160 ierr = TSPreStep(ts);CHKERRQ(ierr); 161 while (PETSC_TRUE) { 162 ts->ptime += current_time_step; 163 ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr); 164 ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr); 165 ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr); 166 ts->nonlinear_its += its; ts->linear_its += lits; 167 ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);CHKERRQ(ierr); 168 if (ok) break; 169 ts->ptime -= current_time_step; 170 current_time_step = ts->time_step; 171 } 172 ierr = VecCopy(pseudo->update,sol);CHKERRQ(ierr); 173 ts->steps++; 174 ierr = TSPostStep(ts);CHKERRQ(ierr); 175 } 176 ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr); 177 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 178 ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr); 179 180 *steps += ts->steps; 181 *ptime = ts->ptime; 182 PetscFunctionReturn(0); 183 } 184 185 /*------------------------------------------------------------*/ 186 #undef __FUNCT__ 187 #define __FUNCT__ "TSDestroy_Pseudo" 188 static PetscErrorCode TSDestroy_Pseudo(TS ts) 189 { 190 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 191 PetscErrorCode ierr; 192 193 PetscFunctionBegin; 194 if (pseudo->update) {ierr = VecDestroy(pseudo->update);CHKERRQ(ierr);} 195 if (pseudo->func) {ierr = VecDestroy(pseudo->func);CHKERRQ(ierr);} 196 if (pseudo->xdot) {ierr = VecDestroy(pseudo->xdot);CHKERRQ(ierr);} 197 ierr = PetscFree(pseudo);CHKERRQ(ierr); 198 PetscFunctionReturn(0); 199 } 200 201 202 /*------------------------------------------------------------*/ 203 204 #undef __FUNCT__ 205 #define __FUNCT__ "TSPseudoGetXdot" 206 /* 207 Compute Xdot = (X^{n+1}-X^n)/dt) = 0 208 */ 209 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot) 210 { 211 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 212 PetscScalar mdt = 1.0/ts->time_step,*xnp1,*xn,*xdot; 213 PetscErrorCode ierr; 214 PetscInt i,n; 215 216 PetscFunctionBegin; 217 ierr = VecGetArray(ts->vec_sol,&xn);CHKERRQ(ierr); 218 ierr = VecGetArray(X,&xnp1);CHKERRQ(ierr); 219 ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 220 ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr); 221 for (i=0; i<n; i++) { 222 xdot[i] = mdt*(xnp1[i] - xn[i]); 223 } 224 ierr = VecRestoreArray(ts->vec_sol,&xn);CHKERRQ(ierr); 225 ierr = VecRestoreArray(X,&xnp1);CHKERRQ(ierr); 226 ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr); 227 *Xdot = pseudo->xdot; 228 PetscFunctionReturn(0); 229 } 230 231 #undef __FUNCT__ 232 #define __FUNCT__ "SNESTSFormFunction_Pseudo" 233 /* 234 The transient residual is 235 236 F(U^{n+1},(U^{n+1}-U^n)/dt) = 0 237 238 or for ODE, 239 240 (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0 241 242 This is the function that must be evaluated for transient simulation and for 243 finite difference Jacobians. On the first Newton step, this algorithm uses 244 a guess of U^{n+1} = U^n in which case the transient term vanishes and the 245 residual is actually the steady state residual. Pseudotransient 246 continuation as described in the literature is a linearly implicit 247 algorithm, it only takes this one Newton step with the steady state 248 residual, and then advances to the next time step. 249 */ 250 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts) 251 { 252 Vec Xdot; 253 PetscErrorCode ierr; 254 255 PetscFunctionBegin; 256 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 257 ierr = TSComputeIFunction(ts,ts->ptime,X,Xdot,Y);CHKERRQ(ierr); 258 PetscFunctionReturn(0); 259 } 260 261 #undef __FUNCT__ 262 #define __FUNCT__ "SNESTSFormJacobian_Pseudo" 263 /* 264 This constructs the Jacobian needed for SNES. For DAE, this is 265 266 dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot 267 268 and for ODE: 269 270 J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs. 271 */ 272 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts) 273 { 274 Vec Xdot; 275 PetscErrorCode ierr; 276 277 PetscFunctionBegin; 278 ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr); 279 ierr = TSComputeIJacobian(ts,ts->ptime,X,Xdot,1./ts->time_step,AA,BB,str);CHKERRQ(ierr); 280 PetscFunctionReturn(0); 281 } 282 283 284 #undef __FUNCT__ 285 #define __FUNCT__ "TSSetUp_Pseudo" 286 static PetscErrorCode TSSetUp_Pseudo(TS ts) 287 { 288 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 289 PetscErrorCode ierr; 290 291 PetscFunctionBegin; 292 ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr); 293 ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr); 294 ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr); 295 ierr = SNESSetFunction(ts->snes,pseudo->func,SNESTSFormFunction,ts);CHKERRQ(ierr); 296 /* This is nasty. SNESSetFromOptions() is usually called in TSSetFromOptions(). With -snes_mf_operator, it will 297 replace A and we don't want to mess with that. With -snes_mf, A and B will be replaced as well as the function and 298 context. Note that SNESSetFunction() normally has not been called before SNESSetFromOptions(), so when -snes_mf sets 299 the Jacobian user context to snes->funP, it will actually be NULL. This is not a problem because both snes->funP and 300 snes->jacP should be the TS. */ 301 { 302 Mat A,B; 303 PetscErrorCode (*func)(SNES,Vec,Mat*,Mat*,MatStructure*,void*); 304 void *ctx; 305 ierr = SNESGetJacobian(ts->snes,&A,&B,&func,&ctx);CHKERRQ(ierr); 306 ierr = SNESSetJacobian(ts->snes,A?A:ts->A,B?B:ts->B,func?func:SNESTSFormJacobian,ctx?ctx:ts);CHKERRQ(ierr); 307 } 308 PetscFunctionReturn(0); 309 } 310 /*------------------------------------------------------------*/ 311 312 #undef __FUNCT__ 313 #define __FUNCT__ "TSPseudoMonitorDefault" 314 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx) 315 { 316 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 317 PetscErrorCode ierr; 318 PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx; 319 320 PetscFunctionBegin; 321 if (!ctx) { 322 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 323 } 324 ierr = PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr); 325 if (!ctx) { 326 ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr); 327 } 328 PetscFunctionReturn(0); 329 } 330 331 #undef __FUNCT__ 332 #define __FUNCT__ "TSSetFromOptions_Pseudo" 333 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts) 334 { 335 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 336 PetscErrorCode ierr; 337 PetscTruth flg = PETSC_FALSE; 338 PetscViewerASCIIMonitor viewer; 339 340 PetscFunctionBegin; 341 ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr); 342 ierr = PetscOptionsTruth("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 343 if (flg) { 344 ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr); 345 ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr); 346 } 347 flg = PETSC_FALSE; 348 ierr = PetscOptionsTruth("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr); 349 if (flg) { 350 ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr); 351 } 352 ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr); 353 ierr = PetscOptionsTail();CHKERRQ(ierr); 354 PetscFunctionReturn(0); 355 } 356 357 #undef __FUNCT__ 358 #define __FUNCT__ "TSView_Pseudo" 359 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer) 360 { 361 PetscFunctionBegin; 362 PetscFunctionReturn(0); 363 } 364 365 /* ----------------------------------------------------------------------------- */ 366 #undef __FUNCT__ 367 #define __FUNCT__ "TSPseudoSetVerifyTimeStep" 368 /*@C 369 TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the 370 last timestep. 371 372 Logically Collective on TS 373 374 Input Parameters: 375 + ts - timestep context 376 . dt - user-defined function to verify timestep 377 - ctx - [optional] user-defined context for private data 378 for the timestep verification routine (may be PETSC_NULL) 379 380 Level: advanced 381 382 Calling sequence of func: 383 . func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag); 384 385 . update - latest solution vector 386 . ctx - [optional] timestep context 387 . newdt - the timestep to use for the next step 388 . flag - flag indicating whether the last time step was acceptable 389 390 Notes: 391 The routine set here will be called by TSPseudoVerifyTimeStep() 392 during the timestepping process. 393 394 .keywords: timestep, pseudo, set, verify 395 396 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep() 397 @*/ 398 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx) 399 { 400 PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *); 401 402 PetscFunctionBegin; 403 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 404 405 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr); 406 if (f) { 407 ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr); 408 } 409 PetscFunctionReturn(0); 410 } 411 412 #undef __FUNCT__ 413 #define __FUNCT__ "TSPseudoSetTimeStepIncrement" 414 /*@ 415 TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to 416 dt when using the TSPseudoDefaultTimeStep() routine. 417 418 Logically Collective on TS 419 420 Input Parameters: 421 + ts - the timestep context 422 - inc - the scaling factor >= 1.0 423 424 Options Database Key: 425 $ -ts_pseudo_increment <increment> 426 427 Level: advanced 428 429 .keywords: timestep, pseudo, set, increment 430 431 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 432 @*/ 433 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc) 434 { 435 PetscErrorCode ierr,(*f)(TS,PetscReal); 436 437 PetscFunctionBegin; 438 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 439 PetscValidLogicalCollectiveReal(ts,inc,2); 440 441 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)(void))&f);CHKERRQ(ierr); 442 if (f) { 443 ierr = (*f)(ts,inc);CHKERRQ(ierr); 444 } 445 PetscFunctionReturn(0); 446 } 447 448 #undef __FUNCT__ 449 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt" 450 /*@ 451 TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep 452 is computed via the formula 453 $ dt = initial_dt*initial_fnorm/current_fnorm 454 rather than the default update, 455 $ dt = current_dt*previous_fnorm/current_fnorm. 456 457 Logically Collective on TS 458 459 Input Parameter: 460 . ts - the timestep context 461 462 Options Database Key: 463 $ -ts_pseudo_increment_dt_from_initial_dt 464 465 Level: advanced 466 467 .keywords: timestep, pseudo, set, increment 468 469 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep() 470 @*/ 471 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt(TS ts) 472 { 473 PetscErrorCode ierr,(*f)(TS); 474 475 PetscFunctionBegin; 476 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 477 478 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)(void))&f);CHKERRQ(ierr); 479 if (f) { 480 ierr = (*f)(ts);CHKERRQ(ierr); 481 } 482 PetscFunctionReturn(0); 483 } 484 485 486 #undef __FUNCT__ 487 #define __FUNCT__ "TSPseudoSetTimeStep" 488 /*@C 489 TSPseudoSetTimeStep - Sets the user-defined routine to be 490 called at each pseudo-timestep to update the timestep. 491 492 Logically Collective on TS 493 494 Input Parameters: 495 + ts - timestep context 496 . dt - function to compute timestep 497 - ctx - [optional] user-defined context for private data 498 required by the function (may be PETSC_NULL) 499 500 Level: intermediate 501 502 Calling sequence of func: 503 . func (TS ts,PetscReal *newdt,void *ctx); 504 505 . newdt - the newly computed timestep 506 . ctx - [optional] timestep context 507 508 Notes: 509 The routine set here will be called by TSPseudoComputeTimeStep() 510 during the timestepping process. 511 512 .keywords: timestep, pseudo, set 513 514 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep() 515 @*/ 516 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx) 517 { 518 PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *); 519 520 PetscFunctionBegin; 521 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 522 523 ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr); 524 if (f) { 525 ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr); 526 } 527 PetscFunctionReturn(0); 528 } 529 530 /* ----------------------------------------------------------------------------- */ 531 532 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/ 533 EXTERN_C_BEGIN 534 #undef __FUNCT__ 535 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo" 536 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx) 537 { 538 TS_Pseudo *pseudo; 539 540 PetscFunctionBegin; 541 pseudo = (TS_Pseudo*)ts->data; 542 pseudo->verify = dt; 543 pseudo->verifyctx = ctx; 544 PetscFunctionReturn(0); 545 } 546 EXTERN_C_END 547 548 EXTERN_C_BEGIN 549 #undef __FUNCT__ 550 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo" 551 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc) 552 { 553 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 554 555 PetscFunctionBegin; 556 pseudo->dt_increment = inc; 557 PetscFunctionReturn(0); 558 } 559 EXTERN_C_END 560 561 EXTERN_C_BEGIN 562 #undef __FUNCT__ 563 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo" 564 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts) 565 { 566 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 567 568 PetscFunctionBegin; 569 pseudo->increment_dt_from_initial_dt = PETSC_TRUE; 570 PetscFunctionReturn(0); 571 } 572 EXTERN_C_END 573 574 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/ 575 EXTERN_C_BEGIN 576 #undef __FUNCT__ 577 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo" 578 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx) 579 { 580 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 581 582 PetscFunctionBegin; 583 pseudo->dt = dt; 584 pseudo->dtctx = ctx; 585 PetscFunctionReturn(0); 586 } 587 EXTERN_C_END 588 589 /* ----------------------------------------------------------------------------- */ 590 /*MC 591 TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping 592 593 This method solves equations of the form 594 595 $ F(X,Xdot) = 0 596 597 for steady state using the iteration 598 599 $ [G'] S = -F(X,0) 600 $ X += S 601 602 where 603 604 $ G(Y) = F(Y,(Y-X)/dt) 605 606 This is linearly-implicit Euler with the residual always evaluated "at steady 607 state". See note below. 608 609 Options database keys: 610 + -ts_pseudo_increment <real> - ratio of increase dt 611 - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt 612 613 Level: beginner 614 615 References: 616 Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003. 617 C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998. 618 619 Notes: 620 The residual computed by this method includes the transient term (Xdot is computed instead of 621 always being zero), but since the prediction from the last step is always the solution from the 622 last step, on the first Newton iteration we have 623 624 $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0 625 626 Therefore, the linear system solved by the first Newton iteration is equivalent to the one 627 described above and in the papers. If the user chooses to perform multiple Newton iterations, the 628 algorithm is no longer the one described in the referenced papers. 629 630 .seealso: TSCreate(), TS, TSSetType() 631 632 M*/ 633 EXTERN_C_BEGIN 634 #undef __FUNCT__ 635 #define __FUNCT__ "TSCreate_Pseudo" 636 PetscErrorCode PETSCTS_DLLEXPORT TSCreate_Pseudo(TS ts) 637 { 638 TS_Pseudo *pseudo; 639 PetscErrorCode ierr; 640 641 PetscFunctionBegin; 642 ts->ops->destroy = TSDestroy_Pseudo; 643 ts->ops->view = TSView_Pseudo; 644 645 if (ts->problem_type == TS_LINEAR) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Only for nonlinear problems"); 646 ts->ops->setup = TSSetUp_Pseudo; 647 ts->ops->step = TSStep_Pseudo; 648 ts->ops->setfromoptions = TSSetFromOptions_Pseudo; 649 ts->ops->snesfunction = SNESTSFormFunction_Pseudo; 650 ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo; 651 652 /* create the required nonlinear solver context */ 653 ierr = SNESCreate(((PetscObject)ts)->comm,&ts->snes);CHKERRQ(ierr); 654 ierr = PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);CHKERRQ(ierr); 655 656 ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr); 657 ts->data = (void*)pseudo; 658 659 pseudo->dt_increment = 1.1; 660 pseudo->increment_dt_from_initial_dt = PETSC_FALSE; 661 pseudo->dt = TSPseudoDefaultTimeStep; 662 663 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C", 664 "TSPseudoSetVerifyTimeStep_Pseudo", 665 TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr); 666 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C", 667 "TSPseudoSetTimeStepIncrement_Pseudo", 668 TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr); 669 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C", 670 "TSPseudoIncrementDtFromInitialDt_Pseudo", 671 TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr); 672 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C", 673 "TSPseudoSetTimeStep_Pseudo", 674 TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr); 675 PetscFunctionReturn(0); 676 } 677 EXTERN_C_END 678 679 #undef __FUNCT__ 680 #define __FUNCT__ "TSPseudoDefaultTimeStep" 681 /*@C 682 TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping. 683 Use with TSPseudoSetTimeStep(). 684 685 Collective on TS 686 687 Input Parameters: 688 . ts - the timestep context 689 . dtctx - unused timestep context 690 691 Output Parameter: 692 . newdt - the timestep to use for the next step 693 694 Level: advanced 695 696 .keywords: timestep, pseudo, default 697 698 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep() 699 @*/ 700 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx) 701 { 702 TS_Pseudo *pseudo = (TS_Pseudo*)ts->data; 703 PetscReal inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous; 704 PetscErrorCode ierr; 705 706 PetscFunctionBegin; 707 ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr); 708 ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr); 709 if (pseudo->initial_fnorm == 0.0) { 710 /* first time through so compute initial function norm */ 711 pseudo->initial_fnorm = pseudo->fnorm; 712 fnorm_previous = pseudo->fnorm; 713 } 714 if (pseudo->fnorm == 0.0) { 715 *newdt = 1.e12*inc*ts->time_step; 716 } else if (pseudo->increment_dt_from_initial_dt) { 717 *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm; 718 } else { 719 *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm; 720 } 721 pseudo->fnorm_previous = pseudo->fnorm; 722 PetscFunctionReturn(0); 723 } 724