1 /* 2 Code for timestepping with Rosenbrock W methods 3 4 Notes: 5 The general system is written as 6 7 G(t,X,Xdot) = F(t,X) 8 9 where G represents the stiff part of the physics and F represents the non-stiff part. 10 This method is designed to be linearly implicit on G and can use an approximate and lagged Jacobian. 11 12 */ 13 #include <private/tsimpl.h> /*I "petscts.h" I*/ 14 15 #include <../src/mat/blockinvert.h> 16 17 static const TSRosWType TSRosWDefault = TSROSWRA34PW2; 18 static PetscBool TSRosWRegisterAllCalled; 19 static PetscBool TSRosWPackageInitialized; 20 21 typedef struct _RosWTableau *RosWTableau; 22 struct _RosWTableau { 23 char *name; 24 PetscInt order; /* Classical approximation order of the method */ 25 PetscInt s; /* Number of stages */ 26 PetscReal *A; /* Propagation table, strictly lower triangular */ 27 PetscReal *Gamma; /* Stage table, lower triangular with nonzero diagonal */ 28 PetscBool *GammaZeroDiag; /* Diagonal entries that are zero in stage table Gamma, vector indicating explicit statages */ 29 PetscReal *GammaExplicitCorr; /* Coefficients for correction terms needed for explicit stages in transformed variables*/ 30 PetscReal *b; /* Step completion table */ 31 PetscReal *bembed; /* Step completion table for embedded method of order one less */ 32 PetscReal *ASum; /* Row sum of A */ 33 PetscReal *GammaSum; /* Row sum of Gamma, only needed for non-autonomous systems */ 34 PetscReal *At; /* Propagation table in transformed variables */ 35 PetscReal *bt; /* Step completion table in transformed variables */ 36 PetscReal *bembedt; /* Step completion table of order one less in transformed variables */ 37 PetscReal *GammaInv; /* Inverse of Gamma, used for transformed variables */ 38 PetscReal ccfl; /* Placeholder for CFL coefficient relative to forward Euler */ 39 }; 40 typedef struct _RosWTableauLink *RosWTableauLink; 41 struct _RosWTableauLink { 42 struct _RosWTableau tab; 43 RosWTableauLink next; 44 }; 45 static RosWTableauLink RosWTableauList; 46 47 typedef struct { 48 RosWTableau tableau; 49 Vec *Y; /* States computed during the step, used to complete the step */ 50 Vec Ydot; /* Work vector holding Ydot during residual evaluation */ 51 Vec Ystage; /* Work vector for the state value at each stage */ 52 Vec Zdot; /* Ydot = Zdot + shift*Y */ 53 Vec Zstage; /* Y = Zstage + Y */ 54 PetscScalar *work; /* Scalar work space of length number of stages, used to prepare VecMAXPY() */ 55 PetscReal shift; 56 PetscReal stage_time; 57 PetscReal stage_explicit; /* Flag indicates that the current stage is explicit */ 58 PetscBool recompute_jacobian; /* Recompute the Jacobian at each stage, default is to freeze the Jacobian at the start of each step */ 59 TSStepStatus status; 60 } TS_RosW; 61 62 /*MC 63 TSROSWTHETA1 - One stage first order L-stable Rosenbrock-W scheme (aka theta method). 64 65 Only an approximate Jacobian is needed. 66 67 Level: intermediate 68 69 .seealso: TSROSW 70 M*/ 71 72 /*MC 73 TSROSWTHETA2 - One stage second order A-stable Rosenbrock-W scheme (aka theta method). 74 75 Only an approximate Jacobian is needed. 76 77 Level: intermediate 78 79 .seealso: TSROSW 80 M*/ 81 82 /*MC 83 TSROSW2M - Two stage second order L-stable Rosenbrock-W scheme. 84 85 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2P. 86 87 Level: intermediate 88 89 .seealso: TSROSW 90 M*/ 91 92 /*MC 93 TSROSW2P - Two stage second order L-stable Rosenbrock-W scheme. 94 95 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2M. 96 97 Level: intermediate 98 99 .seealso: TSROSW 100 M*/ 101 102 /*MC 103 TSROSWRA3PW - Three stage third order Rosenbrock-W scheme for PDAE of index 1. 104 105 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. 106 107 This is strongly A-stable with R(infty) = 0.73. The embedded method of order 2 is strongly A-stable with R(infty) = 0.73. 108 109 References: 110 Rang and Angermann, New Rosenbrock-W methods of order 3 for partial differential algebraic equations of index 1, 2005. 111 112 Level: intermediate 113 114 .seealso: TSROSW 115 M*/ 116 117 /*MC 118 TSROSWRA34PW2 - Four stage third order L-stable Rosenbrock-W scheme for PDAE of index 1. 119 120 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. 121 122 This is strongly A-stable with R(infty) = 0. The embedded method of order 2 is strongly A-stable with R(infty) = 0.48. 123 124 References: 125 Rang and Angermann, New Rosenbrock-W methods of order 3 for partial differential algebraic equations of index 1, 2005. 126 127 Level: intermediate 128 129 .seealso: TSROSW 130 M*/ 131 132 /*MC 133 TSROSWRODAS3 - Four stage third order L-stable Rosenbrock scheme 134 135 By default, the Jacobian is only recomputed once per step. 136 137 Both the third order and embedded second order methods are stiffly accurate and L-stable. 138 139 References: 140 Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997. 141 142 Level: intermediate 143 144 .seealso: TSROSW, TSROSWSANDU3 145 M*/ 146 147 /*MC 148 TSROSWSANDU3 - Three stage third order L-stable Rosenbrock scheme 149 150 By default, the Jacobian is only recomputed once per step. 151 152 The third order method is L-stable, but not stiffly accurate. 153 The second order embedded method is strongly A-stable with R(infty) = 0.5. 154 The internal stages are L-stable. 155 This method is called ROS3 in the paper. 156 157 References: 158 Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997. 159 160 Level: intermediate 161 162 .seealso: TSROSW, TSROSWRODAS3 163 M*/ 164 165 /*MC 166 TSROSWASSP3P3S1C - A-stable Rosenbrock-W method with SSP explicit part, third order, three stages 167 168 By default, the Jacobian is only recomputed once per step. 169 170 A-stable SPP explicit order 3, 3 stages, CFL 1 (eff = 1/3) 171 172 References: 173 Emil Constantinescu 174 175 Level: intermediate 176 177 .seealso: TSROSW, TSROSWLASSP3P4S2C, TSROSWLLSSP3P4S2C, SSP 178 M*/ 179 180 /*MC 181 TSROSWLASSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, three stages 182 183 By default, the Jacobian is only recomputed once per step. 184 185 L-stable (A-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2) 186 187 References: 188 Emil Constantinescu 189 190 Level: intermediate 191 192 .seealso: TSROSW, TSROSWASSP3P3S1C, TSROSWLLSSP3P4S2C, TSSSP 193 M*/ 194 195 /*MC 196 TSROSWLLSSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, three stages 197 198 By default, the Jacobian is only recomputed once per step. 199 200 L-stable (L-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2) 201 202 References: 203 Emil Constantinescu 204 205 Level: intermediate 206 207 .seealso: TSROSW, TSROSWASSP3P3S1C, TSROSWLASSP3P4S2C, TSSSP 208 M*/ 209 210 #undef __FUNCT__ 211 #define __FUNCT__ "TSRosWRegisterAll" 212 /*@C 213 TSRosWRegisterAll - Registers all of the additive Runge-Kutta implicit-explicit methods in TSRosW 214 215 Not Collective, but should be called by all processes which will need the schemes to be registered 216 217 Level: advanced 218 219 .keywords: TS, TSRosW, register, all 220 221 .seealso: TSRosWRegisterDestroy() 222 @*/ 223 PetscErrorCode TSRosWRegisterAll(void) 224 { 225 PetscErrorCode ierr; 226 227 PetscFunctionBegin; 228 if (TSRosWRegisterAllCalled) PetscFunctionReturn(0); 229 TSRosWRegisterAllCalled = PETSC_TRUE; 230 231 { 232 const PetscReal 233 A = 0, 234 Gamma = 1, 235 b = 1; 236 ierr = TSRosWRegister(TSROSWTHETA1,1,1,&A,&Gamma,&b,PETSC_NULL);CHKERRQ(ierr); 237 } 238 239 { 240 const PetscReal 241 A= 0, 242 Gamma = 0.5, 243 b = 1; 244 ierr = TSRosWRegister(TSROSWTHETA2,2,1,&A,&Gamma,&b,PETSC_NULL);CHKERRQ(ierr); 245 } 246 247 { 248 const PetscReal g = 1. + 1./PetscSqrtReal(2.0); 249 const PetscReal 250 A[2][2] = {{0,0}, {1.,0}}, 251 Gamma[2][2] = {{g,0}, {-2.*g,g}}, 252 b[2] = {0.5,0.5}, 253 b1[2] = {1.0,0.0}; 254 ierr = TSRosWRegister(TSROSW2P,2,2,&A[0][0],&Gamma[0][0],b,b1);CHKERRQ(ierr); 255 } 256 { 257 const PetscReal g = 1. - 1./PetscSqrtReal(2.0); 258 const PetscReal 259 A[2][2] = {{0,0}, {1.,0}}, 260 Gamma[2][2] = {{g,0}, {-2.*g,g}}, 261 b[2] = {0.5,0.5}, 262 b1[2] = {1.0,0.0}; 263 ierr = TSRosWRegister(TSROSW2M,2,2,&A[0][0],&Gamma[0][0],b,b1);CHKERRQ(ierr); 264 } 265 { 266 const PetscReal g = 7.8867513459481287e-01; 267 const PetscReal 268 A[3][3] = {{0,0,0}, 269 {1.5773502691896257e+00,0,0}, 270 {0.5,0,0}}, 271 Gamma[3][3] = {{g,0,0}, 272 {-1.5773502691896257e+00,g,0}, 273 {-6.7075317547305480e-01,1.7075317547305482e-01,g}}, 274 b[3] = {1.0566243270259355e-01,4.9038105676657971e-02,8.4529946162074843e-01}, 275 b2[3] = {-1.7863279495408180e-01,1./3.,8.4529946162074843e-01}; 276 ierr = TSRosWRegister(TSROSWRA3PW,3,3,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 277 } 278 { 279 const PetscReal g = 4.3586652150845900e-01; 280 const PetscReal 281 A[4][4] = {{0,0,0,0}, 282 {8.7173304301691801e-01,0,0,0}, 283 {8.4457060015369423e-01,-1.1299064236484185e-01,0,0}, 284 {0,0,1.,0}}, 285 Gamma[4][4] = {{g,0,0,0}, 286 {-8.7173304301691801e-01,g,0,0}, 287 {-9.0338057013044082e-01,5.4180672388095326e-02,g,0}, 288 {2.4212380706095346e-01,-1.2232505839045147e+00,5.4526025533510214e-01,g}}, 289 b[4] = {2.4212380706095346e-01,-1.2232505839045147e+00,1.5452602553351020e+00,4.3586652150845900e-01}, 290 b2[4] = {3.7810903145819369e-01,-9.6042292212423178e-02,5.0000000000000000e-01,2.1793326075422950e-01}; 291 ierr = TSRosWRegister(TSROSWRA34PW2,3,4,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 292 } 293 { 294 const PetscReal g = 0.5; 295 const PetscReal 296 A[4][4] = {{0,0,0,0}, 297 {0,0,0,0}, 298 {1.,0,0,0}, 299 {0.75,-0.25,0.5,0}}, 300 Gamma[4][4] = {{g,0,0,0}, 301 {1.,g,0,0}, 302 {-0.25,-0.25,g,0}, 303 {1./12,1./12,-2./3,g}}, 304 b[4] = {5./6,-1./6,-1./6,0.5}, 305 b2[4] = {0.75,-0.25,0.5,0}; 306 ierr = TSRosWRegister(TSROSWRODAS3,3,4,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 307 } 308 { 309 const PetscReal g = 0.43586652150845899941601945119356; 310 const PetscReal 311 A[3][3] = {{0,0,0}, 312 {g,0,0}, 313 {g,0,0}}, 314 Gamma[3][3] = {{g,0,0}, 315 {-0.19294655696029095575009695436041,g,0}, 316 {0,1.74927148125794685173529749738960,g}}, 317 b[3] = {-0.75457412385404315829818998646589,1.94100407061964420292840123379419,-0.18642994676560104463021124732829}, 318 b2[3] = {-1.53358745784149585370766523913002,2.81745131148625772213931745457622,-0.28386385364476186843165221544619}; 319 ierr = TSRosWRegister(TSROSWSANDU3,3,3,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 320 } 321 { 322 const PetscReal s3 = PetscSqrtReal(3.),g = (3.0+s3)/6.0; 323 const PetscReal 324 A[3][3] = {{0,0,0}, 325 {1,0,0}, 326 {0.25,0.25,0}}, 327 Gamma[3][3] = {{0,0,0}, 328 {(-3.0-s3)/6.0,g,0}, 329 {(-3.0-s3)/24.0,(-3.0-s3)/8.0,g}}, 330 b[3] = {1./6.,1./6.,2./3.}, 331 b2[3] = {1./4.,1./4.,1./2.}; 332 ierr = TSRosWRegister(TSROSWASSP3P3S1C,3,3,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 333 } 334 335 { 336 const PetscReal 337 A[4][4] = {{0,0,0,0}, 338 {1./2.,0,0,0}, 339 {1./2.,1./2.,0,0}, 340 {1./6.,1./6.,1./6.,0}}, 341 Gamma[4][4] = {{1./2.,0,0,0}, 342 {0.0,1./4.,0,0}, 343 {-2.,-2./3.,2./3.,0}, 344 {1./2.,5./36.,-2./9,0}}, 345 b[4] = {1./6.,1./6.,1./6.,1./2.}, 346 b2[4] = {1./8.,3./4.,1./8.,0}; 347 ierr = TSRosWRegister(TSROSWLASSP3P4S2C,3,4,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 348 } 349 350 { 351 const PetscReal 352 A[4][4] = {{0,0,0,0}, 353 {1./2.,0,0,0}, 354 {1./2.,1./2.,0,0}, 355 {1./6.,1./6.,1./6.,0}}, 356 Gamma[4][4] = {{1./2.,0,0,0}, 357 {0.0,3./4.,0,0}, 358 {-2./3.,-23./9.,2./9.,0}, 359 {1./18.,65./108.,-2./27,0}}, 360 b[4] = {1./6.,1./6.,1./6.,1./2.}, 361 b2[4] = {3./16.,10./16.,3./16.,0}; 362 ierr = TSRosWRegister(TSROSWLLSSP3P4S2C,3,4,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 363 } 364 365 { 366 PetscReal A[4][4],Gamma[4][4],b[4],b2[4]; 367 368 Gamma[0][0]=0.4358665215084589994160194475295062513822671686978816; 369 Gamma[0][1]=0; Gamma[0][2]=0; Gamma[0][3]=0; 370 Gamma[1][0]=-1.997527830934941248426324674704153457289527280554476; 371 Gamma[1][1]=0.4358665215084589994160194475295062513822671686978816; 372 Gamma[1][2]=0; Gamma[1][3]=0; 373 Gamma[2][0]=-1.007948511795029620852002345345404191008352770119903; 374 Gamma[2][1]=-0.004648958462629345562774289390054679806993396798458131; 375 Gamma[2][2]=0.4358665215084589994160194475295062513822671686978816; 376 Gamma[2][3]=0; 377 Gamma[3][0]=-0.6685429734233467180451604600279552604364311322650783; 378 Gamma[3][1]=0.6056625986449338476089525334450053439525178740492984; 379 Gamma[3][2]=-0.9717899277217721234705114616271378792182450260943198; 380 Gamma[3][3]=0; 381 382 A[0][0]=0; A[0][1]=0; A[0][2]=0; A[0][3]=0; 383 A[1][0]=0.8717330430169179988320388950590125027645343373957631; 384 A[1][1]=0; A[1][2]=0; A[1][3]=0; 385 A[2][0]=0.5275890119763004115618079766722914408876108660811028; 386 A[2][1]=0.07241098802369958843819203208518599088698057726988732; 387 A[2][2]=0; A[2][3]=0; 388 A[3][0]=0.3990960076760701320627260685975778145384666450351314; 389 A[3][1]=-0.4375576546135194437228463747348862825846903771419953; 390 A[3][2]=1.038461646937449311660120300601880176655352737312713; 391 A[3][3]=0; 392 393 b[0]=0.1876410243467238251612921333138006734899663569186926; 394 b[1]=-0.5952974735769549480478230473706443582188442040780541; 395 b[2]=0.9717899277217721234705114616271378792182450260943198; 396 b[3]=0.4358665215084589994160194475295062513822671686978816; 397 398 b2[0]=0.2147402862233891404862383521089097657790734483804460; 399 b2[1]=-0.4851622638849390928209050538171743017757490232519684; 400 b2[2]=0.8687250025203875511662123688667549217531982787600080; 401 b2[3]=0.4016969751411624011684543450940068201770721128357014; 402 403 ierr = TSRosWRegister(TSROSWARK3,3,4,&A[0][0],&Gamma[0][0],b,b2);CHKERRQ(ierr); 404 } 405 406 PetscFunctionReturn(0); 407 } 408 409 #undef __FUNCT__ 410 #define __FUNCT__ "TSRosWRegisterDestroy" 411 /*@C 412 TSRosWRegisterDestroy - Frees the list of schemes that were registered by TSRosWRegister(). 413 414 Not Collective 415 416 Level: advanced 417 418 .keywords: TSRosW, register, destroy 419 .seealso: TSRosWRegister(), TSRosWRegisterAll(), TSRosWRegisterDynamic() 420 @*/ 421 PetscErrorCode TSRosWRegisterDestroy(void) 422 { 423 PetscErrorCode ierr; 424 RosWTableauLink link; 425 426 PetscFunctionBegin; 427 while ((link = RosWTableauList)) { 428 RosWTableau t = &link->tab; 429 RosWTableauList = link->next; 430 ierr = PetscFree5(t->A,t->Gamma,t->b,t->ASum,t->GammaSum);CHKERRQ(ierr); 431 ierr = PetscFree5(t->At,t->bt,t->GammaInv,t->GammaZeroDiag,t->GammaExplicitCorr);CHKERRQ(ierr); 432 ierr = PetscFree2(t->bembed,t->bembedt);CHKERRQ(ierr); 433 ierr = PetscFree(t->name);CHKERRQ(ierr); 434 ierr = PetscFree(link);CHKERRQ(ierr); 435 } 436 TSRosWRegisterAllCalled = PETSC_FALSE; 437 PetscFunctionReturn(0); 438 } 439 440 #undef __FUNCT__ 441 #define __FUNCT__ "TSRosWInitializePackage" 442 /*@C 443 TSRosWInitializePackage - This function initializes everything in the TSRosW package. It is called 444 from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to TSCreate_RosW() 445 when using static libraries. 446 447 Input Parameter: 448 path - The dynamic library path, or PETSC_NULL 449 450 Level: developer 451 452 .keywords: TS, TSRosW, initialize, package 453 .seealso: PetscInitialize() 454 @*/ 455 PetscErrorCode TSRosWInitializePackage(const char path[]) 456 { 457 PetscErrorCode ierr; 458 459 PetscFunctionBegin; 460 if (TSRosWPackageInitialized) PetscFunctionReturn(0); 461 TSRosWPackageInitialized = PETSC_TRUE; 462 ierr = TSRosWRegisterAll();CHKERRQ(ierr); 463 ierr = PetscRegisterFinalize(TSRosWFinalizePackage);CHKERRQ(ierr); 464 PetscFunctionReturn(0); 465 } 466 467 #undef __FUNCT__ 468 #define __FUNCT__ "TSRosWFinalizePackage" 469 /*@C 470 TSRosWFinalizePackage - This function destroys everything in the TSRosW package. It is 471 called from PetscFinalize(). 472 473 Level: developer 474 475 .keywords: Petsc, destroy, package 476 .seealso: PetscFinalize() 477 @*/ 478 PetscErrorCode TSRosWFinalizePackage(void) 479 { 480 PetscErrorCode ierr; 481 482 PetscFunctionBegin; 483 TSRosWPackageInitialized = PETSC_FALSE; 484 ierr = TSRosWRegisterDestroy();CHKERRQ(ierr); 485 PetscFunctionReturn(0); 486 } 487 488 #undef __FUNCT__ 489 #define __FUNCT__ "TSRosWRegister" 490 /*@C 491 TSRosWRegister - register a Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation 492 493 Not Collective, but the same schemes should be registered on all processes on which they will be used 494 495 Input Parameters: 496 + name - identifier for method 497 . order - approximation order of method 498 . s - number of stages, this is the dimension of the matrices below 499 . A - Table of propagated stage coefficients (dimension s*s, row-major), strictly lower triangular 500 . Gamma - Table of coefficients in implicit stage equations (dimension s*s, row-major), lower triangular with nonzero diagonal 501 . b - Step completion table (dimension s) 502 - bembed - Step completion table for a scheme of order one less (dimension s, PETSC_NULL if no embedded scheme is available) 503 504 Notes: 505 Several Rosenbrock W methods are provided, this function is only needed to create new methods. 506 507 Level: advanced 508 509 .keywords: TS, register 510 511 .seealso: TSRosW 512 @*/ 513 PetscErrorCode TSRosWRegister(const TSRosWType name,PetscInt order,PetscInt s, 514 const PetscReal A[],const PetscReal Gamma[],const PetscReal b[],const PetscReal bembed[]) 515 { 516 PetscErrorCode ierr; 517 RosWTableauLink link; 518 RosWTableau t; 519 PetscInt i,j,k; 520 PetscScalar *GammaInv; 521 522 PetscFunctionBegin; 523 PetscValidCharPointer(name,1); 524 PetscValidPointer(A,4); 525 PetscValidPointer(Gamma,5); 526 PetscValidPointer(b,6); 527 if (bembed) PetscValidPointer(bembed,7); 528 529 ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr); 530 ierr = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr); 531 t = &link->tab; 532 ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr); 533 t->order = order; 534 t->s = s; 535 ierr = PetscMalloc5(s*s,PetscReal,&t->A,s*s,PetscReal,&t->Gamma,s,PetscReal,&t->b,s,PetscReal,&t->ASum,s,PetscReal,&t->GammaSum);CHKERRQ(ierr); 536 ierr = PetscMalloc5(s*s,PetscReal,&t->At,s,PetscReal,&t->bt,s*s,PetscReal,&t->GammaInv,s,PetscBool,&t->GammaZeroDiag,s*s,PetscReal,&t->GammaExplicitCorr);CHKERRQ(ierr); 537 ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr); 538 ierr = PetscMemcpy(t->Gamma,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr); 539 ierr = PetscMemcpy(t->GammaExplicitCorr,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr); 540 ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr); 541 if (bembed) { 542 ierr = PetscMalloc2(s,PetscReal,&t->bembed,s,PetscReal,&t->bembedt);CHKERRQ(ierr); 543 ierr = PetscMemcpy(t->bembed,bembed,s*sizeof(bembed[0]));CHKERRQ(ierr); 544 } 545 for (i=0; i<s; i++) { 546 t->ASum[i] = 0; 547 t->GammaSum[i] = 0; 548 for (j=0; j<s; j++) { 549 t->ASum[i] += A[i*s+j]; 550 t->GammaSum[i] += Gamma[i*s+j]; 551 } 552 } 553 ierr = PetscMalloc(s*s*sizeof(PetscScalar),&GammaInv);CHKERRQ(ierr); /* Need to use Scalar for inverse, then convert back to Real */ 554 for (i=0; i<s*s; i++) GammaInv[i] = Gamma[i]; 555 for (i=0; i<s; i++) { 556 if (Gamma[i*s+i] == 0.0) { 557 GammaInv[i*s+i] = 1.0; 558 t->GammaZeroDiag[i] = PETSC_TRUE; 559 } else { 560 t->GammaZeroDiag[i] = PETSC_FALSE; 561 } 562 } 563 564 switch (s) { 565 case 1: GammaInv[0] = 1./GammaInv[0]; break; 566 case 2: ierr = Kernel_A_gets_inverse_A_2(GammaInv,0);CHKERRQ(ierr); break; 567 case 3: ierr = Kernel_A_gets_inverse_A_3(GammaInv,0);CHKERRQ(ierr); break; 568 case 4: ierr = Kernel_A_gets_inverse_A_4(GammaInv,0);CHKERRQ(ierr); break; 569 case 5: { 570 PetscInt ipvt5[5]; 571 MatScalar work5[5*5]; 572 ierr = Kernel_A_gets_inverse_A_5(GammaInv,ipvt5,work5,0);CHKERRQ(ierr); break; 573 } 574 case 6: ierr = Kernel_A_gets_inverse_A_6(GammaInv,0);CHKERRQ(ierr); break; 575 case 7: ierr = Kernel_A_gets_inverse_A_7(GammaInv,0);CHKERRQ(ierr); break; 576 default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for %D stages",s); 577 } 578 for (i=0; i<s*s; i++) t->GammaInv[i] = PetscRealPart(GammaInv[i]); 579 ierr = PetscFree(GammaInv);CHKERRQ(ierr); 580 581 for (i=0; i<s; i++) { 582 for (k=0; k<i+1; k++) { 583 t->GammaExplicitCorr[i*s+k]=(t->GammaExplicitCorr[i*s+k])*(t->GammaInv[k*s+k]); 584 for (j=k+1; j<i+1; j++) { 585 t->GammaExplicitCorr[i*s+k]+=(t->GammaExplicitCorr[i*s+j])*(t->GammaInv[j*s+k]); 586 } 587 } 588 } 589 590 for (i=0; i<s; i++) { 591 for (j=0; j<s; j++) { 592 t->At[i*s+j] = 0; 593 for (k=0; k<s; k++) { 594 t->At[i*s+j] += t->A[i*s+k] * t->GammaInv[k*s+j]; 595 } 596 } 597 t->bt[i] = 0; 598 for (j=0; j<s; j++) { 599 t->bt[i] += t->b[j] * t->GammaInv[j*s+i]; 600 } 601 if (bembed) { 602 t->bembedt[i] = 0; 603 for (j=0; j<s; j++) { 604 t->bembedt[i] += t->bembed[j] * t->GammaInv[j*s+i]; 605 } 606 } 607 } 608 t->ccfl = 1.0; /* Fix this */ 609 610 link->next = RosWTableauList; 611 RosWTableauList = link; 612 PetscFunctionReturn(0); 613 } 614 615 #undef __FUNCT__ 616 #define __FUNCT__ "TSEvaluateStep_RosW" 617 /* 618 The step completion formula is 619 620 x1 = x0 + b^T Y 621 622 where Y is the multi-vector of stages corrections. This function can be called before or after ts->vec_sol has been 623 updated. Suppose we have a completion formula b and an embedded formula be of different order. We can write 624 625 x1e = x0 + be^T Y 626 = x1 - b^T Y + be^T Y 627 = x1 + (be - b)^T Y 628 629 so we can evaluate the method of different order even after the step has been optimistically completed. 630 */ 631 static PetscErrorCode TSEvaluateStep_RosW(TS ts,PetscInt order,Vec X,PetscBool *done) 632 { 633 TS_RosW *ros = (TS_RosW*)ts->data; 634 RosWTableau tab = ros->tableau; 635 PetscScalar *w = ros->work; 636 PetscInt i; 637 PetscErrorCode ierr; 638 639 PetscFunctionBegin; 640 if (order == tab->order) { 641 if (ros->status == TS_STEP_INCOMPLETE) { /* Use standard completion formula */ 642 ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr); 643 for (i=0; i<tab->s; i++) w[i] = tab->bt[i]; 644 ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr); 645 } else {ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);} 646 if (done) *done = PETSC_TRUE; 647 PetscFunctionReturn(0); 648 } else if (order == tab->order-1) { 649 if (!tab->bembedt) goto unavailable; 650 if (ros->status == TS_STEP_INCOMPLETE) { /* Use embedded completion formula */ 651 ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr); 652 for (i=0; i<tab->s; i++) w[i] = tab->bembedt[i]; 653 ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr); 654 } else { /* Use rollback-and-recomplete formula (bembedt - bt) */ 655 for (i=0; i<tab->s; i++) w[i] = tab->bembedt[i] - tab->bt[i]; 656 ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr); 657 ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr); 658 } 659 if (done) *done = PETSC_TRUE; 660 PetscFunctionReturn(0); 661 } 662 unavailable: 663 if (done) *done = PETSC_FALSE; 664 else SETERRQ3(((PetscObject)ts)->comm,PETSC_ERR_SUP,"Rosenbrock-W '%s' of order %D cannot evaluate step at order %D",tab->name,tab->order,order); 665 PetscFunctionReturn(0); 666 } 667 668 #undef __FUNCT__ 669 #define __FUNCT__ "TSStep_RosW" 670 static PetscErrorCode TSStep_RosW(TS ts) 671 { 672 TS_RosW *ros = (TS_RosW*)ts->data; 673 RosWTableau tab = ros->tableau; 674 const PetscInt s = tab->s; 675 const PetscReal *At = tab->At,*Gamma = tab->Gamma,*ASum = tab->ASum,*GammaInv = tab->GammaInv; 676 const PetscReal *GammaExplicitCorr = tab->GammaExplicitCorr; 677 const PetscBool *GammaZeroDiag = tab->GammaZeroDiag; 678 PetscScalar *w = ros->work; 679 Vec *Y = ros->Y,Ydot = ros->Ydot,Zdot = ros->Zdot,Zstage = ros->Zstage; 680 SNES snes; 681 TSAdapt adapt; 682 PetscInt i,j,its,lits,reject,next_scheme; 683 PetscReal next_time_step; 684 PetscBool accept; 685 PetscErrorCode ierr; 686 MatStructure str; 687 688 PetscFunctionBegin; 689 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 690 next_time_step = ts->time_step; 691 accept = PETSC_TRUE; 692 ros->status = TS_STEP_INCOMPLETE; 693 694 for (reject=0; reject<ts->max_reject && !ts->reason; reject++,ts->reject++) { 695 const PetscReal h = ts->time_step; 696 for (i=0; i<s; i++) { 697 ros->stage_time = ts->ptime + h*ASum[i]; 698 if (GammaZeroDiag[i]) { 699 ros->stage_explicit = PETSC_TRUE; 700 ros->shift = 1./h; 701 } else { 702 ros->stage_explicit = PETSC_FALSE; 703 ros->shift = 1./(h*Gamma[i*s+i]); 704 } 705 706 ierr = VecCopy(ts->vec_sol,Zstage);CHKERRQ(ierr); 707 for (j=0; j<i; j++) w[j] = At[i*s+j]; 708 ierr = VecMAXPY(Zstage,i,w,Y);CHKERRQ(ierr); 709 710 for (j=0; j<i; j++) w[j] = 1./h * GammaInv[i*s+j]; 711 ierr = VecZeroEntries(Zdot);CHKERRQ(ierr); 712 ierr = VecMAXPY(Zdot,i,w,Y);CHKERRQ(ierr); 713 714 /* Initial guess taken from last stage */ 715 ierr = VecZeroEntries(Y[i]);CHKERRQ(ierr); 716 717 if (!ros->stage_explicit) { 718 if (!ros->recompute_jacobian && !i) { 719 ierr = SNESSetLagJacobian(snes,-2);CHKERRQ(ierr); /* Recompute the Jacobian on this solve, but not again */ 720 } 721 ierr = SNESSolve(snes,PETSC_NULL,Y[i]);CHKERRQ(ierr); 722 ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr); 723 ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr); 724 ts->nonlinear_its += its; ts->linear_its += lits; 725 ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); 726 ierr = TSAdaptCheckStage(adapt,ts,&accept);CHKERRQ(ierr); 727 if (!accept) goto reject_step; 728 } else { 729 Mat J,Jp; 730 ierr = VecZeroEntries(Ydot);CHKERRQ(ierr); /* Evaluate Y[i]=G(t,Ydot=0,Zstage) */ 731 ierr = TSComputeIFunction(ts,ros->stage_time,Zstage,Ydot,Y[i],PETSC_FALSE);CHKERRQ(ierr); 732 ierr = VecScale(Y[i],-1.0); 733 ierr = VecAXPY(Y[i],-1.0,Zdot);CHKERRQ(ierr); /*Y[i]=F(Zstage)-Zdot[=GammaInv*Y]*/ 734 735 ierr = VecZeroEntries(Zstage);CHKERRQ(ierr); /* Zstage = GammaExplicitCorr[i,j] * Y[j] */ 736 for (j=0; j<i; j++) w[j] = GammaExplicitCorr[i*s+j]; 737 ierr = VecMAXPY(Zstage,i,w,Y);CHKERRQ(ierr); 738 /*Y[i] += Y[i] + Jac*Zstage[=Jac*GammaExplicitCorr[i,j] * Y[j]] */ 739 str = SAME_NONZERO_PATTERN; 740 ierr = TSGetIJacobian(ts,&J,&Jp,PETSC_NULL,PETSC_NULL); 741 ierr = TSComputeIJacobian(ts,ros->stage_time,ts->vec_sol,Ydot,0,&J,&Jp,&str,PETSC_FALSE);CHKERRQ(ierr); 742 ierr = MatMult(J,Zstage,Zdot); 743 744 ierr = VecAXPY(Y[i],-1.0,Zdot);CHKERRQ(ierr); 745 ierr = VecScale(Y[i],h); 746 ts->linear_its += 1; 747 } 748 } 749 ierr = TSEvaluateStep(ts,tab->order,ts->vec_sol,PETSC_NULL);CHKERRQ(ierr); 750 ros->status = TS_STEP_PENDING; 751 752 /* Register only the current method as a candidate because we're not supporting multiple candidates yet. */ 753 ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr); 754 ierr = TSAdaptCandidatesClear(adapt);CHKERRQ(ierr); 755 ierr = TSAdaptCandidateAdd(adapt,tab->name,tab->order,1,tab->ccfl,1.*tab->s,PETSC_TRUE);CHKERRQ(ierr); 756 ierr = TSAdaptChoose(adapt,ts,ts->time_step,&next_scheme,&next_time_step,&accept);CHKERRQ(ierr); 757 if (accept) { 758 /* ignore next_scheme for now */ 759 ts->ptime += ts->time_step; 760 ts->time_step = next_time_step; 761 ts->steps++; 762 ros->status = TS_STEP_COMPLETE; 763 break; 764 } else { /* Roll back the current step */ 765 for (i=0; i<s; i++) w[i] = -tab->bt[i]; 766 ierr = VecMAXPY(ts->vec_sol,s,w,Y);CHKERRQ(ierr); 767 ts->time_step = next_time_step; 768 ros->status = TS_STEP_INCOMPLETE; 769 } 770 reject_step: continue; 771 } 772 if (ros->status != TS_STEP_COMPLETE && !ts->reason) ts->reason = TS_DIVERGED_STEP_REJECTED; 773 PetscFunctionReturn(0); 774 } 775 776 #undef __FUNCT__ 777 #define __FUNCT__ "TSInterpolate_RosW" 778 static PetscErrorCode TSInterpolate_RosW(TS ts,PetscReal itime,Vec X) 779 { 780 TS_RosW *ros = (TS_RosW*)ts->data; 781 782 PetscFunctionBegin; 783 SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_SUP,"TSRosW %s does not have an interpolation formula",ros->tableau->name); 784 PetscFunctionReturn(0); 785 } 786 787 /*------------------------------------------------------------*/ 788 #undef __FUNCT__ 789 #define __FUNCT__ "TSReset_RosW" 790 static PetscErrorCode TSReset_RosW(TS ts) 791 { 792 TS_RosW *ros = (TS_RosW*)ts->data; 793 PetscInt s; 794 PetscErrorCode ierr; 795 796 PetscFunctionBegin; 797 if (!ros->tableau) PetscFunctionReturn(0); 798 s = ros->tableau->s; 799 ierr = VecDestroyVecs(s,&ros->Y);CHKERRQ(ierr); 800 ierr = VecDestroy(&ros->Ydot);CHKERRQ(ierr); 801 ierr = VecDestroy(&ros->Ystage);CHKERRQ(ierr); 802 ierr = VecDestroy(&ros->Zdot);CHKERRQ(ierr); 803 ierr = VecDestroy(&ros->Zstage);CHKERRQ(ierr); 804 ierr = PetscFree(ros->work);CHKERRQ(ierr); 805 PetscFunctionReturn(0); 806 } 807 808 #undef __FUNCT__ 809 #define __FUNCT__ "TSDestroy_RosW" 810 static PetscErrorCode TSDestroy_RosW(TS ts) 811 { 812 PetscErrorCode ierr; 813 814 PetscFunctionBegin; 815 ierr = TSReset_RosW(ts);CHKERRQ(ierr); 816 ierr = PetscFree(ts->data);CHKERRQ(ierr); 817 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","",PETSC_NULL);CHKERRQ(ierr); 818 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","",PETSC_NULL);CHKERRQ(ierr); 819 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","",PETSC_NULL);CHKERRQ(ierr); 820 PetscFunctionReturn(0); 821 } 822 823 /* 824 This defines the nonlinear equation that is to be solved with SNES 825 G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0 826 */ 827 #undef __FUNCT__ 828 #define __FUNCT__ "SNESTSFormFunction_RosW" 829 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes,Vec X,Vec F,TS ts) 830 { 831 TS_RosW *ros = (TS_RosW*)ts->data; 832 PetscErrorCode ierr; 833 834 PetscFunctionBegin; 835 ierr = VecWAXPY(ros->Ydot,ros->shift,X,ros->Zdot);CHKERRQ(ierr); /* Ydot = shift*X + Zdot */ 836 ierr = VecWAXPY(ros->Ystage,1.0,X,ros->Zstage);CHKERRQ(ierr); /* Ystage = X + Zstage */ 837 ierr = TSComputeIFunction(ts,ros->stage_time,ros->Ystage,ros->Ydot,F,PETSC_FALSE);CHKERRQ(ierr); 838 PetscFunctionReturn(0); 839 } 840 841 #undef __FUNCT__ 842 #define __FUNCT__ "SNESTSFormJacobian_RosW" 843 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *str,TS ts) 844 { 845 TS_RosW *ros = (TS_RosW*)ts->data; 846 PetscErrorCode ierr; 847 848 PetscFunctionBegin; 849 /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */ 850 ierr = TSComputeIJacobian(ts,ros->stage_time,ros->Ystage,ros->Ydot,ros->shift,A,B,str,PETSC_TRUE);CHKERRQ(ierr); 851 PetscFunctionReturn(0); 852 } 853 854 #undef __FUNCT__ 855 #define __FUNCT__ "TSSetUp_RosW" 856 static PetscErrorCode TSSetUp_RosW(TS ts) 857 { 858 TS_RosW *ros = (TS_RosW*)ts->data; 859 RosWTableau tab = ros->tableau; 860 PetscInt s = tab->s; 861 PetscErrorCode ierr; 862 863 PetscFunctionBegin; 864 if (!ros->tableau) { 865 ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr); 866 } 867 ierr = VecDuplicateVecs(ts->vec_sol,s,&ros->Y);CHKERRQ(ierr); 868 ierr = VecDuplicate(ts->vec_sol,&ros->Ydot);CHKERRQ(ierr); 869 ierr = VecDuplicate(ts->vec_sol,&ros->Ystage);CHKERRQ(ierr); 870 ierr = VecDuplicate(ts->vec_sol,&ros->Zdot);CHKERRQ(ierr); 871 ierr = VecDuplicate(ts->vec_sol,&ros->Zstage);CHKERRQ(ierr); 872 ierr = PetscMalloc(s*sizeof(ros->work[0]),&ros->work);CHKERRQ(ierr); 873 PetscFunctionReturn(0); 874 } 875 /*------------------------------------------------------------*/ 876 877 #undef __FUNCT__ 878 #define __FUNCT__ "TSSetFromOptions_RosW" 879 static PetscErrorCode TSSetFromOptions_RosW(TS ts) 880 { 881 TS_RosW *ros = (TS_RosW*)ts->data; 882 PetscErrorCode ierr; 883 char rostype[256]; 884 885 PetscFunctionBegin; 886 ierr = PetscOptionsHead("RosW ODE solver options");CHKERRQ(ierr); 887 { 888 RosWTableauLink link; 889 PetscInt count,choice; 890 PetscBool flg; 891 const char **namelist; 892 SNES snes; 893 894 ierr = PetscStrncpy(rostype,TSRosWDefault,sizeof rostype);CHKERRQ(ierr); 895 for (link=RosWTableauList,count=0; link; link=link->next,count++) ; 896 ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr); 897 for (link=RosWTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name; 898 ierr = PetscOptionsEList("-ts_rosw_type","Family of Rosenbrock-W method","TSRosWSetType",(const char*const*)namelist,count,rostype,&choice,&flg);CHKERRQ(ierr); 899 ierr = TSRosWSetType(ts,flg ? namelist[choice] : rostype);CHKERRQ(ierr); 900 ierr = PetscFree(namelist);CHKERRQ(ierr); 901 902 ierr = PetscOptionsBool("-ts_rosw_recompute_jacobian","Recompute the Jacobian at each stage","TSRosWSetRecomputeJacobian",ros->recompute_jacobian,&ros->recompute_jacobian,PETSC_NULL);CHKERRQ(ierr); 903 904 /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */ 905 ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr); 906 if (!((PetscObject)snes)->type_name) { 907 ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr); 908 } 909 ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); 910 } 911 ierr = PetscOptionsTail();CHKERRQ(ierr); 912 PetscFunctionReturn(0); 913 } 914 915 #undef __FUNCT__ 916 #define __FUNCT__ "PetscFormatRealArray" 917 static PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[]) 918 { 919 PetscErrorCode ierr; 920 PetscInt i; 921 size_t left,count; 922 char *p; 923 924 PetscFunctionBegin; 925 for (i=0,p=buf,left=len; i<n; i++) { 926 ierr = PetscSNPrintfCount(p,left,fmt,&count,x[i]);CHKERRQ(ierr); 927 if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer"); 928 left -= count; 929 p += count; 930 *p++ = ' '; 931 } 932 p[i ? 0 : -1] = 0; 933 PetscFunctionReturn(0); 934 } 935 936 #undef __FUNCT__ 937 #define __FUNCT__ "TSView_RosW" 938 static PetscErrorCode TSView_RosW(TS ts,PetscViewer viewer) 939 { 940 TS_RosW *ros = (TS_RosW*)ts->data; 941 RosWTableau tab = ros->tableau; 942 PetscBool iascii; 943 PetscErrorCode ierr; 944 945 PetscFunctionBegin; 946 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 947 if (iascii) { 948 const TSRosWType rostype; 949 PetscInt i; 950 PetscReal abscissa[512]; 951 char buf[512]; 952 ierr = TSRosWGetType(ts,&rostype);CHKERRQ(ierr); 953 ierr = PetscViewerASCIIPrintf(viewer," Rosenbrock-W %s\n",rostype);CHKERRQ(ierr); 954 ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->ASum);CHKERRQ(ierr); 955 ierr = PetscViewerASCIIPrintf(viewer," Abscissa of A = %s\n",buf);CHKERRQ(ierr); 956 for (i=0; i<tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i]; 957 ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,abscissa);CHKERRQ(ierr); 958 ierr = PetscViewerASCIIPrintf(viewer," Abscissa of A+Gamma = %s\n",buf);CHKERRQ(ierr); 959 } 960 ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr); 961 PetscFunctionReturn(0); 962 } 963 964 #undef __FUNCT__ 965 #define __FUNCT__ "TSRosWSetType" 966 /*@C 967 TSRosWSetType - Set the type of Rosenbrock-W scheme 968 969 Logically collective 970 971 Input Parameter: 972 + ts - timestepping context 973 - rostype - type of Rosenbrock-W scheme 974 975 Level: beginner 976 977 .seealso: TSRosWGetType(), TSROSW, TSROSW2M, TSROSW2P, TSROSWRA3PW, TSROSWRA34PW2, TSROSWRODAS3, TSROSWSANDU3, TSROSWASSP3P3S1C, TSROSWLASSP3P4S2C, TSROSWLLSSP3P4S2C, TSROSWARK3 978 @*/ 979 PetscErrorCode TSRosWSetType(TS ts,const TSRosWType rostype) 980 { 981 PetscErrorCode ierr; 982 983 PetscFunctionBegin; 984 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 985 ierr = PetscTryMethod(ts,"TSRosWSetType_C",(TS,const TSRosWType),(ts,rostype));CHKERRQ(ierr); 986 PetscFunctionReturn(0); 987 } 988 989 #undef __FUNCT__ 990 #define __FUNCT__ "TSRosWGetType" 991 /*@C 992 TSRosWGetType - Get the type of Rosenbrock-W scheme 993 994 Logically collective 995 996 Input Parameter: 997 . ts - timestepping context 998 999 Output Parameter: 1000 . rostype - type of Rosenbrock-W scheme 1001 1002 Level: intermediate 1003 1004 .seealso: TSRosWGetType() 1005 @*/ 1006 PetscErrorCode TSRosWGetType(TS ts,const TSRosWType *rostype) 1007 { 1008 PetscErrorCode ierr; 1009 1010 PetscFunctionBegin; 1011 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 1012 ierr = PetscUseMethod(ts,"TSRosWGetType_C",(TS,const TSRosWType*),(ts,rostype));CHKERRQ(ierr); 1013 PetscFunctionReturn(0); 1014 } 1015 1016 #undef __FUNCT__ 1017 #define __FUNCT__ "TSRosWSetRecomputeJacobian" 1018 /*@C 1019 TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step. 1020 1021 Logically collective 1022 1023 Input Parameter: 1024 + ts - timestepping context 1025 - flg - PETSC_TRUE to recompute the Jacobian at each stage 1026 1027 Level: intermediate 1028 1029 .seealso: TSRosWGetType() 1030 @*/ 1031 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts,PetscBool flg) 1032 { 1033 PetscErrorCode ierr; 1034 1035 PetscFunctionBegin; 1036 PetscValidHeaderSpecific(ts,TS_CLASSID,1); 1037 ierr = PetscTryMethod(ts,"TSRosWSetRecomputeJacobian_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr); 1038 PetscFunctionReturn(0); 1039 } 1040 1041 EXTERN_C_BEGIN 1042 #undef __FUNCT__ 1043 #define __FUNCT__ "TSRosWGetType_RosW" 1044 PetscErrorCode TSRosWGetType_RosW(TS ts,const TSRosWType *rostype) 1045 { 1046 TS_RosW *ros = (TS_RosW*)ts->data; 1047 PetscErrorCode ierr; 1048 1049 PetscFunctionBegin; 1050 if (!ros->tableau) {ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);} 1051 *rostype = ros->tableau->name; 1052 PetscFunctionReturn(0); 1053 } 1054 #undef __FUNCT__ 1055 #define __FUNCT__ "TSRosWSetType_RosW" 1056 PetscErrorCode TSRosWSetType_RosW(TS ts,const TSRosWType rostype) 1057 { 1058 TS_RosW *ros = (TS_RosW*)ts->data; 1059 PetscErrorCode ierr; 1060 PetscBool match; 1061 RosWTableauLink link; 1062 1063 PetscFunctionBegin; 1064 if (ros->tableau) { 1065 ierr = PetscStrcmp(ros->tableau->name,rostype,&match);CHKERRQ(ierr); 1066 if (match) PetscFunctionReturn(0); 1067 } 1068 for (link = RosWTableauList; link; link=link->next) { 1069 ierr = PetscStrcmp(link->tab.name,rostype,&match);CHKERRQ(ierr); 1070 if (match) { 1071 ierr = TSReset_RosW(ts);CHKERRQ(ierr); 1072 ros->tableau = &link->tab; 1073 PetscFunctionReturn(0); 1074 } 1075 } 1076 SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",rostype); 1077 PetscFunctionReturn(0); 1078 } 1079 1080 #undef __FUNCT__ 1081 #define __FUNCT__ "TSRosWSetRecomputeJacobian_RosW" 1082 PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts,PetscBool flg) 1083 { 1084 TS_RosW *ros = (TS_RosW*)ts->data; 1085 1086 PetscFunctionBegin; 1087 ros->recompute_jacobian = flg; 1088 PetscFunctionReturn(0); 1089 } 1090 EXTERN_C_END 1091 1092 /* ------------------------------------------------------------ */ 1093 /*MC 1094 TSROSW - ODE solver using Rosenbrock-W schemes 1095 1096 These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly 1097 nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part 1098 of the equation using TSSetIFunction() and the non-stiff part with TSSetRHSFunction(). 1099 1100 Notes: 1101 This method currently only works with autonomous ODE and DAE. 1102 1103 Developer notes: 1104 Rosenbrock-W methods are typically specified for autonomous ODE 1105 1106 $ xdot = f(x) 1107 1108 by the stage equations 1109 1110 $ k_i = h f(x_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j 1111 1112 and step completion formula 1113 1114 $ x_1 = x_0 + sum_j b_j k_j 1115 1116 with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(x) 1117 and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner, 1118 we define new variables for the stage equations 1119 1120 $ y_i = gamma_ij k_j 1121 1122 The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define 1123 1124 $ A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-i} 1125 1126 to rewrite the method as 1127 1128 $ [M/(h gamma_ii) - J] y_i = f(x_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j 1129 $ x_1 = x_0 + sum_j bt_j y_j 1130 1131 where we have introduced the mass matrix M. Continue by defining 1132 1133 $ ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j 1134 1135 or, more compactly in tensor notation 1136 1137 $ Ydot = 1/h (Gamma^{-1} \otimes I) Y . 1138 1139 Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current 1140 stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the 1141 equation 1142 1143 $ g(x_0 + sum_j a_ij y_j + y_i, ydot_i) = 0 1144 1145 with initial guess y_i = 0. 1146 1147 Level: beginner 1148 1149 .seealso: TSCreate(), TS, TSSetType(), TSRosWSetType(), TSRosWRegister() 1150 1151 M*/ 1152 EXTERN_C_BEGIN 1153 #undef __FUNCT__ 1154 #define __FUNCT__ "TSCreate_RosW" 1155 PetscErrorCode TSCreate_RosW(TS ts) 1156 { 1157 TS_RosW *ros; 1158 PetscErrorCode ierr; 1159 1160 PetscFunctionBegin; 1161 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) 1162 ierr = TSRosWInitializePackage(PETSC_NULL);CHKERRQ(ierr); 1163 #endif 1164 1165 ts->ops->reset = TSReset_RosW; 1166 ts->ops->destroy = TSDestroy_RosW; 1167 ts->ops->view = TSView_RosW; 1168 ts->ops->setup = TSSetUp_RosW; 1169 ts->ops->step = TSStep_RosW; 1170 ts->ops->interpolate = TSInterpolate_RosW; 1171 ts->ops->evaluatestep = TSEvaluateStep_RosW; 1172 ts->ops->setfromoptions = TSSetFromOptions_RosW; 1173 ts->ops->snesfunction = SNESTSFormFunction_RosW; 1174 ts->ops->snesjacobian = SNESTSFormJacobian_RosW; 1175 1176 ierr = PetscNewLog(ts,TS_RosW,&ros);CHKERRQ(ierr); 1177 ts->data = (void*)ros; 1178 1179 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","TSRosWGetType_RosW",TSRosWGetType_RosW);CHKERRQ(ierr); 1180 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","TSRosWSetType_RosW",TSRosWSetType_RosW);CHKERRQ(ierr); 1181 ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","TSRosWSetRecomputeJacobian_RosW",TSRosWSetRecomputeJacobian_RosW);CHKERRQ(ierr); 1182 PetscFunctionReturn(0); 1183 } 1184 EXTERN_C_END 1185