1 /* 2 Code for timestepping with Rosenbrock W methods 3 4 Notes: 5 The general system is written as 6 7 F(t,U,Udot) = G(t,U) 8 9 where F represents the stiff part of the physics and G represents the non-stiff part. 10 This method is designed to be linearly implicit on F and can use an approximate and lagged Jacobian. 11 12 */ 13 #include <petsc/private/tsimpl.h> /*I "petscts.h" I*/ 14 #include <petscdm.h> 15 16 #include <petsc/private/kernels/blockinvert.h> 17 18 static TSRosWType TSRosWDefault = TSROSWRA34PW2; 19 static PetscBool TSRosWRegisterAllCalled; 20 static PetscBool TSRosWPackageInitialized; 21 22 typedef struct _RosWTableau *RosWTableau; 23 struct _RosWTableau { 24 char *name; 25 PetscInt order; /* Classical approximation order of the method */ 26 PetscInt s; /* Number of stages */ 27 PetscInt pinterp; /* Interpolation order */ 28 PetscReal *A; /* Propagation table, strictly lower triangular */ 29 PetscReal *Gamma; /* Stage table, lower triangular with nonzero diagonal */ 30 PetscBool *GammaZeroDiag; /* Diagonal entries that are zero in stage table Gamma, vector indicating explicit statages */ 31 PetscReal *GammaExplicitCorr; /* Coefficients for correction terms needed for explicit stages in transformed variables*/ 32 PetscReal *b; /* Step completion table */ 33 PetscReal *bembed; /* Step completion table for embedded method of order one less */ 34 PetscReal *ASum; /* Row sum of A */ 35 PetscReal *GammaSum; /* Row sum of Gamma, only needed for non-autonomous systems */ 36 PetscReal *At; /* Propagation table in transformed variables */ 37 PetscReal *bt; /* Step completion table in transformed variables */ 38 PetscReal *bembedt; /* Step completion table of order one less in transformed variables */ 39 PetscReal *GammaInv; /* Inverse of Gamma, used for transformed variables */ 40 PetscReal ccfl; /* Placeholder for CFL coefficient relative to forward Euler */ 41 PetscReal *binterpt; /* Dense output formula */ 42 }; 43 typedef struct _RosWTableauLink *RosWTableauLink; 44 struct _RosWTableauLink { 45 struct _RosWTableau tab; 46 RosWTableauLink next; 47 }; 48 static RosWTableauLink RosWTableauList; 49 50 typedef struct { 51 RosWTableau tableau; 52 Vec *Y; /* States computed during the step, used to complete the step */ 53 Vec Ydot; /* Work vector holding Ydot during residual evaluation */ 54 Vec Ystage; /* Work vector for the state value at each stage */ 55 Vec Zdot; /* Ydot = Zdot + shift*Y */ 56 Vec Zstage; /* Y = Zstage + Y */ 57 Vec vec_sol_prev; /* Solution from the previous step (used for interpolation and rollback)*/ 58 PetscScalar *work; /* Scalar work space of length number of stages, used to prepare VecMAXPY() */ 59 PetscReal scoeff; /* shift = scoeff/dt */ 60 PetscReal stage_time; 61 PetscReal stage_explicit; /* Flag indicates that the current stage is explicit */ 62 PetscBool recompute_jacobian; /* Recompute the Jacobian at each stage, default is to freeze the Jacobian at the start of each step */ 63 TSStepStatus status; 64 } TS_RosW; 65 66 /*MC 67 TSROSWTHETA1 - One stage first order L-stable Rosenbrock-W scheme (aka theta method). 68 69 Only an approximate Jacobian is needed. 70 71 Level: intermediate 72 73 .seealso: [](ch_ts), `TSROSW` 74 M*/ 75 76 /*MC 77 TSROSWTHETA2 - One stage second order A-stable Rosenbrock-W scheme (aka theta method). 78 79 Only an approximate Jacobian is needed. 80 81 Level: intermediate 82 83 .seealso: [](ch_ts), `TSROSW` 84 M*/ 85 86 /*MC 87 TSROSW2M - Two stage second order L-stable Rosenbrock-W scheme. 88 89 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2P. 90 91 Level: intermediate 92 93 .seealso: [](ch_ts), `TSROSW` 94 M*/ 95 96 /*MC 97 TSROSW2P - Two stage second order L-stable Rosenbrock-W scheme. 98 99 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2M. 100 101 Level: intermediate 102 103 .seealso: [](ch_ts), `TSROSW` 104 M*/ 105 106 /*MC 107 TSROSWRA3PW - Three stage third order Rosenbrock-W scheme for PDAE of index 1. 108 109 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. 110 111 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. 112 113 Level: intermediate 114 115 References: 116 . * - Rang and Angermann, New Rosenbrock W methods of order 3 for partial differential algebraic equations of index 1, 2005. 117 118 .seealso: [](ch_ts), `TSROSW` 119 M*/ 120 121 /*MC 122 TSROSWRA34PW2 - Four stage third order L-stable Rosenbrock-W scheme for PDAE of index 1. 123 124 Only an approximate Jacobian is needed. By default, it is only recomputed once per step. 125 126 This is strongly A-stable with R(infty) = 0. The embedded method of order 2 is strongly A-stable with R(infty) = 0.48. 127 128 Level: intermediate 129 130 References: 131 . * - Rang and Angermann, New Rosenbrock W methods of order 3 for partial differential algebraic equations of index 1, 2005. 132 133 .seealso: [](ch_ts), `TSROSW` 134 M*/ 135 136 /*MC 137 TSROSWRODAS3 - Four stage third order L-stable Rosenbrock scheme 138 139 By default, the Jacobian is only recomputed once per step. 140 141 Both the third order and embedded second order methods are stiffly accurate and L-stable. 142 143 Level: intermediate 144 145 References: 146 . * - Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997. 147 148 .seealso: [](ch_ts), `TSROSW`, `TSROSWSANDU3` 149 M*/ 150 151 /*MC 152 TSROSWSANDU3 - Three stage third order L-stable Rosenbrock scheme 153 154 By default, the Jacobian is only recomputed once per step. 155 156 The third order method is L-stable, but not stiffly accurate. 157 The second order embedded method is strongly A-stable with R(infty) = 0.5. 158 The internal stages are L-stable. 159 This method is called ROS3 in the paper. 160 161 Level: intermediate 162 163 References: 164 . * - Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997. 165 166 .seealso: [](ch_ts), `TSROSW`, `TSROSWRODAS3` 167 M*/ 168 169 /*MC 170 TSROSWASSP3P3S1C - A-stable Rosenbrock-W method with SSP explicit part, third order, three stages 171 172 By default, the Jacobian is only recomputed once per step. 173 174 A-stable SPP explicit order 3, 3 stages, CFL 1 (eff = 1/3) 175 176 Level: intermediate 177 178 References: 179 . * - Emil Constantinescu 180 181 .seealso: [](ch_ts), `TSROSW`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `SSP` 182 M*/ 183 184 /*MC 185 TSROSWLASSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, four stages 186 187 By default, the Jacobian is only recomputed once per step. 188 189 L-stable (A-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2) 190 191 Level: intermediate 192 193 References: 194 . * - Emil Constantinescu 195 196 .seealso: [](ch_ts), `TSROSW`, `TSROSWASSP3P3S1C`, `TSROSWLLSSP3P4S2C`, `TSSSP` 197 M*/ 198 199 /*MC 200 TSROSWLLSSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, four stages 201 202 By default, the Jacobian is only recomputed once per step. 203 204 L-stable (L-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2) 205 206 Level: intermediate 207 208 References: 209 . * - Emil Constantinescu 210 211 .seealso: [](ch_ts), `TSROSW`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSSSP` 212 M*/ 213 214 /*MC 215 TSROSWGRK4T - four stage, fourth order Rosenbrock (not W) method from Kaps and Rentrop 216 217 By default, the Jacobian is only recomputed once per step. 218 219 A(89.3 degrees)-stable, |R(infty)| = 0.454. 220 221 This method does not provide a dense output formula. 222 223 Level: intermediate 224 225 References: 226 + * - Kaps and Rentrop, Generalized Runge Kutta methods of order four with stepsize control for stiff ordinary differential equations, 1979. 227 - * - Hairer and Wanner, Solving Ordinary Differential Equations II, Section 4 Table 7.2. 228 229 Hairer's code ros4.f 230 231 .seealso: [](ch_ts), `TSROSW`, `TSROSWSHAMP4`, `TSROSWVELDD4`, `TSROSW4L` 232 M*/ 233 234 /*MC 235 TSROSWSHAMP4 - four stage, fourth order Rosenbrock (not W) method from Shampine 236 237 By default, the Jacobian is only recomputed once per step. 238 239 A-stable, |R(infty)| = 1/3. 240 241 This method does not provide a dense output formula. 242 243 Level: intermediate 244 245 References: 246 + * - Shampine, Implementation of Rosenbrock methods, 1982. 247 - * - Hairer and Wanner, Solving Ordinary Differential Equations II, Section 4 Table 7.2. 248 249 Hairer's code ros4.f 250 251 .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWVELDD4`, `TSROSW4L` 252 M*/ 253 254 /*MC 255 TSROSWVELDD4 - four stage, fourth order Rosenbrock (not W) method from van Veldhuizen 256 257 By default, the Jacobian is only recomputed once per step. 258 259 A(89.5 degrees)-stable, |R(infty)| = 0.24. 260 261 This method does not provide a dense output formula. 262 263 Level: intermediate 264 265 References: 266 + * - van Veldhuizen, D stability and Kaps Rentrop methods, 1984. 267 - * - Hairer and Wanner, Solving Ordinary Differential Equations II, Section 4 Table 7.2. 268 269 Hairer's code ros4.f 270 271 .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSW4L` 272 M*/ 273 274 /*MC 275 TSROSW4L - four stage, fourth order Rosenbrock (not W) method 276 277 By default, the Jacobian is only recomputed once per step. 278 279 A-stable and L-stable 280 281 This method does not provide a dense output formula. 282 283 Level: intermediate 284 285 References: 286 . * - Hairer and Wanner, Solving Ordinary Differential Equations II, Section 4 Table 7.2. 287 288 Hairer's code ros4.f 289 290 .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSW4L` 291 M*/ 292 293 /*@C 294 TSRosWRegisterAll - Registers all of the Rosenbrock-W methods in `TSROSW` 295 296 Not Collective, but should be called by all processes which will need the schemes to be registered 297 298 Level: advanced 299 300 .seealso: [](ch_ts), `TSROSW`, `TSRosWRegisterDestroy()` 301 @*/ 302 PetscErrorCode TSRosWRegisterAll(void) 303 { 304 PetscFunctionBegin; 305 if (TSRosWRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 306 TSRosWRegisterAllCalled = PETSC_TRUE; 307 308 { 309 const PetscReal A = 0; 310 const PetscReal Gamma = 1; 311 const PetscReal b = 1; 312 const PetscReal binterpt = 1; 313 314 PetscCall(TSRosWRegister(TSROSWTHETA1, 1, 1, &A, &Gamma, &b, NULL, 1, &binterpt)); 315 } 316 317 { 318 const PetscReal A = 0; 319 const PetscReal Gamma = 0.5; 320 const PetscReal b = 1; 321 const PetscReal binterpt = 1; 322 323 PetscCall(TSRosWRegister(TSROSWTHETA2, 2, 1, &A, &Gamma, &b, NULL, 1, &binterpt)); 324 } 325 326 { 327 /*const PetscReal g = 1. + 1./PetscSqrtReal(2.0); Direct evaluation: 1.707106781186547524401. Used for setting up arrays of values known at compile time below. */ 328 const PetscReal A[2][2] = 329 { 330 {0, 0}, 331 {1., 0} 332 }, 333 Gamma[2][2] = {{1.707106781186547524401, 0}, {-2. * 1.707106781186547524401, 1.707106781186547524401}}, b[2] = {0.5, 0.5}, b1[2] = {1.0, 0.0}; 334 PetscReal binterpt[2][2]; 335 binterpt[0][0] = 1.707106781186547524401 - 1.0; 336 binterpt[1][0] = 2.0 - 1.707106781186547524401; 337 binterpt[0][1] = 1.707106781186547524401 - 1.5; 338 binterpt[1][1] = 1.5 - 1.707106781186547524401; 339 340 PetscCall(TSRosWRegister(TSROSW2P, 2, 2, &A[0][0], &Gamma[0][0], b, b1, 2, &binterpt[0][0])); 341 } 342 { 343 /*const PetscReal g = 1. - 1./PetscSqrtReal(2.0); Direct evaluation: 0.2928932188134524755992. Used for setting up arrays of values known at compile time below. */ 344 const PetscReal A[2][2] = 345 { 346 {0, 0}, 347 {1., 0} 348 }, 349 Gamma[2][2] = {{0.2928932188134524755992, 0}, {-2. * 0.2928932188134524755992, 0.2928932188134524755992}}, b[2] = {0.5, 0.5}, b1[2] = {1.0, 0.0}; 350 PetscReal binterpt[2][2]; 351 binterpt[0][0] = 0.2928932188134524755992 - 1.0; 352 binterpt[1][0] = 2.0 - 0.2928932188134524755992; 353 binterpt[0][1] = 0.2928932188134524755992 - 1.5; 354 binterpt[1][1] = 1.5 - 0.2928932188134524755992; 355 356 PetscCall(TSRosWRegister(TSROSW2M, 2, 2, &A[0][0], &Gamma[0][0], b, b1, 2, &binterpt[0][0])); 357 } 358 { 359 /*const PetscReal g = 7.8867513459481287e-01; Directly written in-place below */ 360 PetscReal binterpt[3][2]; 361 const PetscReal A[3][3] = 362 { 363 {0, 0, 0}, 364 {1.5773502691896257e+00, 0, 0}, 365 {0.5, 0, 0} 366 }, 367 Gamma[3][3] = {{7.8867513459481287e-01, 0, 0}, {-1.5773502691896257e+00, 7.8867513459481287e-01, 0}, {-6.7075317547305480e-01, -1.7075317547305482e-01, 7.8867513459481287e-01}}, b[3] = {1.0566243270259355e-01, 4.9038105676657971e-02, 8.4529946162074843e-01}, b2[3] = {-1.7863279495408180e-01, 1. / 3., 8.4529946162074843e-01}; 368 369 binterpt[0][0] = -0.8094010767585034; 370 binterpt[1][0] = -0.5; 371 binterpt[2][0] = 2.3094010767585034; 372 binterpt[0][1] = 0.9641016151377548; 373 binterpt[1][1] = 0.5; 374 binterpt[2][1] = -1.4641016151377548; 375 376 PetscCall(TSRosWRegister(TSROSWRA3PW, 3, 3, &A[0][0], &Gamma[0][0], b, b2, 2, &binterpt[0][0])); 377 } 378 { 379 PetscReal binterpt[4][3]; 380 /*const PetscReal g = 4.3586652150845900e-01; Directly written in-place below */ 381 const PetscReal A[4][4] = 382 { 383 {0, 0, 0, 0}, 384 {8.7173304301691801e-01, 0, 0, 0}, 385 {8.4457060015369423e-01, -1.1299064236484185e-01, 0, 0}, 386 {0, 0, 1., 0} 387 }, 388 Gamma[4][4] = {{4.3586652150845900e-01, 0, 0, 0}, {-8.7173304301691801e-01, 4.3586652150845900e-01, 0, 0}, {-9.0338057013044082e-01, 5.4180672388095326e-02, 4.3586652150845900e-01, 0}, {2.4212380706095346e-01, -1.2232505839045147e+00, 5.4526025533510214e-01, 4.3586652150845900e-01}}, b[4] = {2.4212380706095346e-01, -1.2232505839045147e+00, 1.5452602553351020e+00, 4.3586652150845900e-01}, b2[4] = {3.7810903145819369e-01, -9.6042292212423178e-02, 5.0000000000000000e-01, 2.1793326075422950e-01}; 389 390 binterpt[0][0] = 1.0564298455794094; 391 binterpt[1][0] = 2.296429974281067; 392 binterpt[2][0] = -1.307599564525376; 393 binterpt[3][0] = -1.045260255335102; 394 binterpt[0][1] = -1.3864882699759573; 395 binterpt[1][1] = -8.262611700275677; 396 binterpt[2][1] = 7.250979895056055; 397 binterpt[3][1] = 2.398120075195581; 398 binterpt[0][2] = 0.5721822314575016; 399 binterpt[1][2] = 4.742931142090097; 400 binterpt[2][2] = -4.398120075195578; 401 binterpt[3][2] = -0.9169932983520199; 402 403 PetscCall(TSRosWRegister(TSROSWRA34PW2, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0])); 404 } 405 { 406 /* const PetscReal g = 0.5; Directly written in-place below */ 407 const PetscReal A[4][4] = 408 { 409 {0, 0, 0, 0}, 410 {0, 0, 0, 0}, 411 {1., 0, 0, 0}, 412 {0.75, -0.25, 0.5, 0} 413 }, 414 Gamma[4][4] = {{0.5, 0, 0, 0}, {1., 0.5, 0, 0}, {-0.25, -0.25, 0.5, 0}, {1. / 12, 1. / 12, -2. / 3, 0.5}}, b[4] = {5. / 6, -1. / 6, -1. / 6, 0.5}, b2[4] = {0.75, -0.25, 0.5, 0}; 415 416 PetscCall(TSRosWRegister(TSROSWRODAS3, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 0, NULL)); 417 } 418 { 419 /*const PetscReal g = 0.43586652150845899941601945119356; Directly written in-place below */ 420 const PetscReal A[3][3] = 421 { 422 {0, 0, 0}, 423 {0.43586652150845899941601945119356, 0, 0}, 424 {0.43586652150845899941601945119356, 0, 0} 425 }, 426 Gamma[3][3] = {{0.43586652150845899941601945119356, 0, 0}, {-0.19294655696029095575009695436041, 0.43586652150845899941601945119356, 0}, {0, 1.74927148125794685173529749738960, 0.43586652150845899941601945119356}}, b[3] = {-0.75457412385404315829818998646589, 1.94100407061964420292840123379419, -0.18642994676560104463021124732829}, b2[3] = {-1.53358745784149585370766523913002, 2.81745131148625772213931745457622, -0.28386385364476186843165221544619}; 427 428 PetscReal binterpt[3][2]; 429 binterpt[0][0] = 3.793692883777660870425141387941; 430 binterpt[1][0] = -2.918692883777660870425141387941; 431 binterpt[2][0] = 0.125; 432 binterpt[0][1] = -0.725741064379812106687651020584; 433 binterpt[1][1] = 0.559074397713145440020984353917; 434 binterpt[2][1] = 0.16666666666666666666666666666667; 435 436 PetscCall(TSRosWRegister(TSROSWSANDU3, 3, 3, &A[0][0], &Gamma[0][0], b, b2, 2, &binterpt[0][0])); 437 } 438 { 439 /*const PetscReal s3 = PetscSqrtReal(3.),g = (3.0+s3)/6.0; 440 * Direct evaluation: s3 = 1.732050807568877293527; 441 * g = 0.7886751345948128822546; 442 * Values are directly inserted below to ensure availability at compile time (compiler warnings otherwise...) */ 443 const PetscReal A[3][3] = 444 { 445 {0, 0, 0}, 446 {1, 0, 0}, 447 {0.25, 0.25, 0} 448 }, 449 Gamma[3][3] = {{0, 0, 0}, {(-3.0 - 1.732050807568877293527) / 6.0, 0.7886751345948128822546, 0}, {(-3.0 - 1.732050807568877293527) / 24.0, (-3.0 - 1.732050807568877293527) / 8.0, 0.7886751345948128822546}}, b[3] = {1. / 6., 1. / 6., 2. / 3.}, b2[3] = {1. / 4., 1. / 4., 1. / 2.}; 450 PetscReal binterpt[3][2]; 451 452 binterpt[0][0] = 0.089316397477040902157517886164709; 453 binterpt[1][0] = -0.91068360252295909784248211383529; 454 binterpt[2][0] = 1.8213672050459181956849642276706; 455 binterpt[0][1] = 0.077350269189625764509148780501957; 456 binterpt[1][1] = 1.077350269189625764509148780502; 457 binterpt[2][1] = -1.1547005383792515290182975610039; 458 459 PetscCall(TSRosWRegister(TSROSWASSP3P3S1C, 3, 3, &A[0][0], &Gamma[0][0], b, b2, 2, &binterpt[0][0])); 460 } 461 462 { 463 const PetscReal A[4][4] = 464 { 465 {0, 0, 0, 0}, 466 {1. / 2., 0, 0, 0}, 467 {1. / 2., 1. / 2., 0, 0}, 468 {1. / 6., 1. / 6., 1. / 6., 0} 469 }, 470 Gamma[4][4] = {{1. / 2., 0, 0, 0}, {0.0, 1. / 4., 0, 0}, {-2., -2. / 3., 2. / 3., 0}, {1. / 2., 5. / 36., -2. / 9, 0}}, b[4] = {1. / 6., 1. / 6., 1. / 6., 1. / 2.}, b2[4] = {1. / 8., 3. / 4., 1. / 8., 0}; 471 PetscReal binterpt[4][3]; 472 473 binterpt[0][0] = 6.25; 474 binterpt[1][0] = -30.25; 475 binterpt[2][0] = 1.75; 476 binterpt[3][0] = 23.25; 477 binterpt[0][1] = -9.75; 478 binterpt[1][1] = 58.75; 479 binterpt[2][1] = -3.25; 480 binterpt[3][1] = -45.75; 481 binterpt[0][2] = 3.6666666666666666666666666666667; 482 binterpt[1][2] = -28.333333333333333333333333333333; 483 binterpt[2][2] = 1.6666666666666666666666666666667; 484 binterpt[3][2] = 23.; 485 486 PetscCall(TSRosWRegister(TSROSWLASSP3P4S2C, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0])); 487 } 488 489 { 490 const PetscReal A[4][4] = 491 { 492 {0, 0, 0, 0}, 493 {1. / 2., 0, 0, 0}, 494 {1. / 2., 1. / 2., 0, 0}, 495 {1. / 6., 1. / 6., 1. / 6., 0} 496 }, 497 Gamma[4][4] = {{1. / 2., 0, 0, 0}, {0.0, 3. / 4., 0, 0}, {-2. / 3., -23. / 9., 2. / 9., 0}, {1. / 18., 65. / 108., -2. / 27, 0}}, b[4] = {1. / 6., 1. / 6., 1. / 6., 1. / 2.}, b2[4] = {3. / 16., 10. / 16., 3. / 16., 0}; 498 PetscReal binterpt[4][3]; 499 500 binterpt[0][0] = 1.6911764705882352941176470588235; 501 binterpt[1][0] = 3.6813725490196078431372549019608; 502 binterpt[2][0] = 0.23039215686274509803921568627451; 503 binterpt[3][0] = -4.6029411764705882352941176470588; 504 binterpt[0][1] = -0.95588235294117647058823529411765; 505 binterpt[1][1] = -6.2401960784313725490196078431373; 506 binterpt[2][1] = -0.31862745098039215686274509803922; 507 binterpt[3][1] = 7.5147058823529411764705882352941; 508 binterpt[0][2] = -0.56862745098039215686274509803922; 509 binterpt[1][2] = 2.7254901960784313725490196078431; 510 binterpt[2][2] = 0.25490196078431372549019607843137; 511 binterpt[3][2] = -2.4117647058823529411764705882353; 512 513 PetscCall(TSRosWRegister(TSROSWLLSSP3P4S2C, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0])); 514 } 515 516 { 517 PetscReal A[4][4], Gamma[4][4], b[4], b2[4]; 518 PetscReal binterpt[4][3]; 519 520 Gamma[0][0] = 0.4358665215084589994160194475295062513822671686978816; 521 Gamma[0][1] = 0; 522 Gamma[0][2] = 0; 523 Gamma[0][3] = 0; 524 Gamma[1][0] = -1.997527830934941248426324674704153457289527280554476; 525 Gamma[1][1] = 0.4358665215084589994160194475295062513822671686978816; 526 Gamma[1][2] = 0; 527 Gamma[1][3] = 0; 528 Gamma[2][0] = -1.007948511795029620852002345345404191008352770119903; 529 Gamma[2][1] = -0.004648958462629345562774289390054679806993396798458131; 530 Gamma[2][2] = 0.4358665215084589994160194475295062513822671686978816; 531 Gamma[2][3] = 0; 532 Gamma[3][0] = -0.6685429734233467180451604600279552604364311322650783; 533 Gamma[3][1] = 0.6056625986449338476089525334450053439525178740492984; 534 Gamma[3][2] = -0.9717899277217721234705114616271378792182450260943198; 535 Gamma[3][3] = 0; 536 537 A[0][0] = 0; 538 A[0][1] = 0; 539 A[0][2] = 0; 540 A[0][3] = 0; 541 A[1][0] = 0.8717330430169179988320388950590125027645343373957631; 542 A[1][1] = 0; 543 A[1][2] = 0; 544 A[1][3] = 0; 545 A[2][0] = 0.5275890119763004115618079766722914408876108660811028; 546 A[2][1] = 0.07241098802369958843819203208518599088698057726988732; 547 A[2][2] = 0; 548 A[2][3] = 0; 549 A[3][0] = 0.3990960076760701320627260685975778145384666450351314; 550 A[3][1] = -0.4375576546135194437228463747348862825846903771419953; 551 A[3][2] = 1.038461646937449311660120300601880176655352737312713; 552 A[3][3] = 0; 553 554 b[0] = 0.1876410243467238251612921333138006734899663569186926; 555 b[1] = -0.5952974735769549480478230473706443582188442040780541; 556 b[2] = 0.9717899277217721234705114616271378792182450260943198; 557 b[3] = 0.4358665215084589994160194475295062513822671686978816; 558 559 b2[0] = 0.2147402862233891404862383521089097657790734483804460; 560 b2[1] = -0.4851622638849390928209050538171743017757490232519684; 561 b2[2] = 0.8687250025203875511662123688667549217531982787600080; 562 b2[3] = 0.4016969751411624011684543450940068201770721128357014; 563 564 binterpt[0][0] = 2.2565812720167954547104627844105; 565 binterpt[1][0] = 1.349166413351089573796243820819; 566 binterpt[2][0] = -2.4695174540533503758652847586647; 567 binterpt[3][0] = -0.13623023131453465264142184656474; 568 binterpt[0][1] = -3.0826699111559187902922463354557; 569 binterpt[1][1] = -2.4689115685996042534544925650515; 570 binterpt[2][1] = 5.7428279814696677152129332773553; 571 binterpt[3][1] = -0.19124650171414467146619437684812; 572 binterpt[0][2] = 1.0137296634858471607430756831148; 573 binterpt[1][2] = 0.52444768167155973161042570784064; 574 binterpt[2][2] = -2.3015205996945452158771370439586; 575 binterpt[3][2] = 0.76334325453713832352363565300308; 576 577 PetscCall(TSRosWRegister(TSROSWARK3, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0])); 578 } 579 PetscCall(TSRosWRegisterRos4(TSROSWGRK4T, 0.231, PETSC_DEFAULT, PETSC_DEFAULT, 0, -0.1282612945269037e+01)); 580 PetscCall(TSRosWRegisterRos4(TSROSWSHAMP4, 0.5, PETSC_DEFAULT, PETSC_DEFAULT, 0, 125. / 108.)); 581 PetscCall(TSRosWRegisterRos4(TSROSWVELDD4, 0.22570811482256823492, PETSC_DEFAULT, PETSC_DEFAULT, 0, -1.355958941201148)); 582 PetscCall(TSRosWRegisterRos4(TSROSW4L, 0.57282, PETSC_DEFAULT, PETSC_DEFAULT, 0, -1.093502252409163)); 583 PetscFunctionReturn(PETSC_SUCCESS); 584 } 585 586 /*@C 587 TSRosWRegisterDestroy - Frees the list of schemes that were registered by `TSRosWRegister()`. 588 589 Not Collective 590 591 Level: advanced 592 593 .seealso: [](ch_ts), `TSRosWRegister()`, `TSRosWRegisterAll()` 594 @*/ 595 PetscErrorCode TSRosWRegisterDestroy(void) 596 { 597 RosWTableauLink link; 598 599 PetscFunctionBegin; 600 while ((link = RosWTableauList)) { 601 RosWTableau t = &link->tab; 602 RosWTableauList = link->next; 603 PetscCall(PetscFree5(t->A, t->Gamma, t->b, t->ASum, t->GammaSum)); 604 PetscCall(PetscFree5(t->At, t->bt, t->GammaInv, t->GammaZeroDiag, t->GammaExplicitCorr)); 605 PetscCall(PetscFree2(t->bembed, t->bembedt)); 606 PetscCall(PetscFree(t->binterpt)); 607 PetscCall(PetscFree(t->name)); 608 PetscCall(PetscFree(link)); 609 } 610 TSRosWRegisterAllCalled = PETSC_FALSE; 611 PetscFunctionReturn(PETSC_SUCCESS); 612 } 613 614 /*@C 615 TSRosWInitializePackage - This function initializes everything in the `TSROSW` package. It is called 616 from `TSInitializePackage()`. 617 618 Level: developer 619 620 .seealso: [](ch_ts), `TSROSW`, `PetscInitialize()`, `TSRosWFinalizePackage()` 621 @*/ 622 PetscErrorCode TSRosWInitializePackage(void) 623 { 624 PetscFunctionBegin; 625 if (TSRosWPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS); 626 TSRosWPackageInitialized = PETSC_TRUE; 627 PetscCall(TSRosWRegisterAll()); 628 PetscCall(PetscRegisterFinalize(TSRosWFinalizePackage)); 629 PetscFunctionReturn(PETSC_SUCCESS); 630 } 631 632 /*@C 633 TSRosWFinalizePackage - This function destroys everything in the `TSROSW` package. It is 634 called from `PetscFinalize()`. 635 636 Level: developer 637 638 .seealso: [](ch_ts), `TSROSW`, `PetscFinalize()`, `TSRosWInitializePackage()` 639 @*/ 640 PetscErrorCode TSRosWFinalizePackage(void) 641 { 642 PetscFunctionBegin; 643 TSRosWPackageInitialized = PETSC_FALSE; 644 PetscCall(TSRosWRegisterDestroy()); 645 PetscFunctionReturn(PETSC_SUCCESS); 646 } 647 648 /*@C 649 TSRosWRegister - register a `TSROSW`, Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation 650 651 Not Collective, but the same schemes should be registered on all processes on which they will be used 652 653 Input Parameters: 654 + name - identifier for method 655 . order - approximation order of method 656 . s - number of stages, this is the dimension of the matrices below 657 . A - Table of propagated stage coefficients (dimension s*s, row-major), strictly lower triangular 658 . Gamma - Table of coefficients in implicit stage equations (dimension s*s, row-major), lower triangular with nonzero diagonal 659 . b - Step completion table (dimension s) 660 . bembed - Step completion table for a scheme of order one less (dimension s, NULL if no embedded scheme is available) 661 . pinterp - Order of the interpolation scheme, equal to the number of columns of binterpt 662 - binterpt - Coefficients of the interpolation formula (dimension s*pinterp) 663 664 Level: advanced 665 666 Note: 667 Several Rosenbrock W methods are provided, this function is only needed to create new methods. 668 669 .seealso: [](ch_ts), `TSROSW` 670 @*/ 671 PetscErrorCode TSRosWRegister(TSRosWType name, PetscInt order, PetscInt s, const PetscReal A[], const PetscReal Gamma[], const PetscReal b[], const PetscReal bembed[], PetscInt pinterp, const PetscReal binterpt[]) 672 { 673 RosWTableauLink link; 674 RosWTableau t; 675 PetscInt i, j, k; 676 PetscScalar *GammaInv; 677 678 PetscFunctionBegin; 679 PetscValidCharPointer(name, 1); 680 PetscValidRealPointer(A, 4); 681 PetscValidRealPointer(Gamma, 5); 682 PetscValidRealPointer(b, 6); 683 if (bembed) PetscValidRealPointer(bembed, 7); 684 685 PetscCall(TSRosWInitializePackage()); 686 PetscCall(PetscNew(&link)); 687 t = &link->tab; 688 PetscCall(PetscStrallocpy(name, &t->name)); 689 t->order = order; 690 t->s = s; 691 PetscCall(PetscMalloc5(s * s, &t->A, s * s, &t->Gamma, s, &t->b, s, &t->ASum, s, &t->GammaSum)); 692 PetscCall(PetscMalloc5(s * s, &t->At, s, &t->bt, s * s, &t->GammaInv, s, &t->GammaZeroDiag, s * s, &t->GammaExplicitCorr)); 693 PetscCall(PetscArraycpy(t->A, A, s * s)); 694 PetscCall(PetscArraycpy(t->Gamma, Gamma, s * s)); 695 PetscCall(PetscArraycpy(t->GammaExplicitCorr, Gamma, s * s)); 696 PetscCall(PetscArraycpy(t->b, b, s)); 697 if (bembed) { 698 PetscCall(PetscMalloc2(s, &t->bembed, s, &t->bembedt)); 699 PetscCall(PetscArraycpy(t->bembed, bembed, s)); 700 } 701 for (i = 0; i < s; i++) { 702 t->ASum[i] = 0; 703 t->GammaSum[i] = 0; 704 for (j = 0; j < s; j++) { 705 t->ASum[i] += A[i * s + j]; 706 t->GammaSum[i] += Gamma[i * s + j]; 707 } 708 } 709 PetscCall(PetscMalloc1(s * s, &GammaInv)); /* Need to use Scalar for inverse, then convert back to Real */ 710 for (i = 0; i < s * s; i++) GammaInv[i] = Gamma[i]; 711 for (i = 0; i < s; i++) { 712 if (Gamma[i * s + i] == 0.0) { 713 GammaInv[i * s + i] = 1.0; 714 t->GammaZeroDiag[i] = PETSC_TRUE; 715 } else { 716 t->GammaZeroDiag[i] = PETSC_FALSE; 717 } 718 } 719 720 switch (s) { 721 case 1: 722 GammaInv[0] = 1. / GammaInv[0]; 723 break; 724 case 2: 725 PetscCall(PetscKernel_A_gets_inverse_A_2(GammaInv, 0, PETSC_FALSE, NULL)); 726 break; 727 case 3: 728 PetscCall(PetscKernel_A_gets_inverse_A_3(GammaInv, 0, PETSC_FALSE, NULL)); 729 break; 730 case 4: 731 PetscCall(PetscKernel_A_gets_inverse_A_4(GammaInv, 0, PETSC_FALSE, NULL)); 732 break; 733 case 5: { 734 PetscInt ipvt5[5]; 735 MatScalar work5[5 * 5]; 736 PetscCall(PetscKernel_A_gets_inverse_A_5(GammaInv, ipvt5, work5, 0, PETSC_FALSE, NULL)); 737 break; 738 } 739 case 6: 740 PetscCall(PetscKernel_A_gets_inverse_A_6(GammaInv, 0, PETSC_FALSE, NULL)); 741 break; 742 case 7: 743 PetscCall(PetscKernel_A_gets_inverse_A_7(GammaInv, 0, PETSC_FALSE, NULL)); 744 break; 745 default: 746 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented for %" PetscInt_FMT " stages", s); 747 } 748 for (i = 0; i < s * s; i++) t->GammaInv[i] = PetscRealPart(GammaInv[i]); 749 PetscCall(PetscFree(GammaInv)); 750 751 for (i = 0; i < s; i++) { 752 for (k = 0; k < i + 1; k++) { 753 t->GammaExplicitCorr[i * s + k] = (t->GammaExplicitCorr[i * s + k]) * (t->GammaInv[k * s + k]); 754 for (j = k + 1; j < i + 1; j++) t->GammaExplicitCorr[i * s + k] += (t->GammaExplicitCorr[i * s + j]) * (t->GammaInv[j * s + k]); 755 } 756 } 757 758 for (i = 0; i < s; i++) { 759 for (j = 0; j < s; j++) { 760 t->At[i * s + j] = 0; 761 for (k = 0; k < s; k++) t->At[i * s + j] += t->A[i * s + k] * t->GammaInv[k * s + j]; 762 } 763 t->bt[i] = 0; 764 for (j = 0; j < s; j++) t->bt[i] += t->b[j] * t->GammaInv[j * s + i]; 765 if (bembed) { 766 t->bembedt[i] = 0; 767 for (j = 0; j < s; j++) t->bembedt[i] += t->bembed[j] * t->GammaInv[j * s + i]; 768 } 769 } 770 t->ccfl = 1.0; /* Fix this */ 771 772 t->pinterp = pinterp; 773 PetscCall(PetscMalloc1(s * pinterp, &t->binterpt)); 774 PetscCall(PetscArraycpy(t->binterpt, binterpt, s * pinterp)); 775 link->next = RosWTableauList; 776 RosWTableauList = link; 777 PetscFunctionReturn(PETSC_SUCCESS); 778 } 779 780 /*@C 781 TSRosWRegisterRos4 - register a fourth order Rosenbrock scheme by providing parameter choices 782 783 Not Collective, but the same schemes should be registered on all processes on which they will be used 784 785 Input Parameters: 786 + name - identifier for method 787 . gamma - leading coefficient (diagonal entry) 788 . a2 - design parameter, see Table 7.2 of Hairer&Wanner 789 . a3 - design parameter or PETSC_DEFAULT to satisfy one of the order five conditions (Eq 7.22) 790 . b3 - design parameter, see Table 7.2 of Hairer&Wanner 791 - e4 - design parameter for embedded method, see coefficient E4 in ros4.f code from Hairer 792 793 Level: developer 794 795 Notes: 796 This routine encodes the design of fourth order Rosenbrock methods as described in Hairer and Wanner volume 2. 797 It is used here to implement several methods from the book and can be used to experiment with new methods. 798 It was written this way instead of by copying coefficients in order to provide better than double precision satisfaction of the order conditions. 799 800 .seealso: [](ch_ts), `TSRosW`, `TSRosWRegister()` 801 @*/ 802 PetscErrorCode TSRosWRegisterRos4(TSRosWType name, PetscReal gamma, PetscReal a2, PetscReal a3, PetscReal b3, PetscReal e4) 803 { 804 /* Declare numeric constants so they can be quad precision without being truncated at double */ 805 const PetscReal one = 1, two = 2, three = 3, four = 4, five = 5, six = 6, eight = 8, twelve = 12, twenty = 20, twentyfour = 24, p32 = one / six - gamma + gamma * gamma, p42 = one / eight - gamma / three, p43 = one / twelve - gamma / three, p44 = one / twentyfour - gamma / two + three / two * gamma * gamma - gamma * gamma * gamma, p56 = one / twenty - gamma / four; 806 PetscReal a4, a32, a42, a43, b1, b2, b4, beta2p, beta3p, beta4p, beta32, beta42, beta43, beta32beta2p, beta4jbetajp; 807 PetscReal A[4][4], Gamma[4][4], b[4], bm[4]; 808 PetscScalar M[3][3], rhs[3]; 809 810 PetscFunctionBegin; 811 /* Step 1: choose Gamma (input) */ 812 /* Step 2: choose a2,a3,a4; b1,b2,b3,b4 to satisfy order conditions */ 813 if (a3 == (PetscReal)PETSC_DEFAULT) a3 = (one / five - a2 / four) / (one / four - a2 / three); /* Eq 7.22 */ 814 a4 = a3; /* consequence of 7.20 */ 815 816 /* Solve order conditions 7.15a, 7.15c, 7.15e */ 817 M[0][0] = one; 818 M[0][1] = one; 819 M[0][2] = one; /* 7.15a */ 820 M[1][0] = 0.0; 821 M[1][1] = a2 * a2; 822 M[1][2] = a4 * a4; /* 7.15c */ 823 M[2][0] = 0.0; 824 M[2][1] = a2 * a2 * a2; 825 M[2][2] = a4 * a4 * a4; /* 7.15e */ 826 rhs[0] = one - b3; 827 rhs[1] = one / three - a3 * a3 * b3; 828 rhs[2] = one / four - a3 * a3 * a3 * b3; 829 PetscCall(PetscKernel_A_gets_inverse_A_3(&M[0][0], 0, PETSC_FALSE, NULL)); 830 b1 = PetscRealPart(M[0][0] * rhs[0] + M[0][1] * rhs[1] + M[0][2] * rhs[2]); 831 b2 = PetscRealPart(M[1][0] * rhs[0] + M[1][1] * rhs[1] + M[1][2] * rhs[2]); 832 b4 = PetscRealPart(M[2][0] * rhs[0] + M[2][1] * rhs[1] + M[2][2] * rhs[2]); 833 834 /* Step 3 */ 835 beta43 = (p56 - a2 * p43) / (b4 * a3 * a3 * (a3 - a2)); /* 7.21 */ 836 beta32beta2p = p44 / (b4 * beta43); /* 7.15h */ 837 beta4jbetajp = (p32 - b3 * beta32beta2p) / b4; 838 M[0][0] = b2; 839 M[0][1] = b3; 840 M[0][2] = b4; 841 M[1][0] = a4 * a4 * beta32beta2p - a3 * a3 * beta4jbetajp; 842 M[1][1] = a2 * a2 * beta4jbetajp; 843 M[1][2] = -a2 * a2 * beta32beta2p; 844 M[2][0] = b4 * beta43 * a3 * a3 - p43; 845 M[2][1] = -b4 * beta43 * a2 * a2; 846 M[2][2] = 0; 847 rhs[0] = one / two - gamma; 848 rhs[1] = 0; 849 rhs[2] = -a2 * a2 * p32; 850 PetscCall(PetscKernel_A_gets_inverse_A_3(&M[0][0], 0, PETSC_FALSE, NULL)); 851 beta2p = PetscRealPart(M[0][0] * rhs[0] + M[0][1] * rhs[1] + M[0][2] * rhs[2]); 852 beta3p = PetscRealPart(M[1][0] * rhs[0] + M[1][1] * rhs[1] + M[1][2] * rhs[2]); 853 beta4p = PetscRealPart(M[2][0] * rhs[0] + M[2][1] * rhs[1] + M[2][2] * rhs[2]); 854 855 /* Step 4: back-substitute */ 856 beta32 = beta32beta2p / beta2p; 857 beta42 = (beta4jbetajp - beta43 * beta3p) / beta2p; 858 859 /* Step 5: 7.15f and 7.20, then 7.16 */ 860 a43 = 0; 861 a32 = p42 / (b3 * a3 * beta2p + b4 * a4 * beta2p); 862 a42 = a32; 863 864 A[0][0] = 0; 865 A[0][1] = 0; 866 A[0][2] = 0; 867 A[0][3] = 0; 868 A[1][0] = a2; 869 A[1][1] = 0; 870 A[1][2] = 0; 871 A[1][3] = 0; 872 A[2][0] = a3 - a32; 873 A[2][1] = a32; 874 A[2][2] = 0; 875 A[2][3] = 0; 876 A[3][0] = a4 - a43 - a42; 877 A[3][1] = a42; 878 A[3][2] = a43; 879 A[3][3] = 0; 880 Gamma[0][0] = gamma; 881 Gamma[0][1] = 0; 882 Gamma[0][2] = 0; 883 Gamma[0][3] = 0; 884 Gamma[1][0] = beta2p - A[1][0]; 885 Gamma[1][1] = gamma; 886 Gamma[1][2] = 0; 887 Gamma[1][3] = 0; 888 Gamma[2][0] = beta3p - beta32 - A[2][0]; 889 Gamma[2][1] = beta32 - A[2][1]; 890 Gamma[2][2] = gamma; 891 Gamma[2][3] = 0; 892 Gamma[3][0] = beta4p - beta42 - beta43 - A[3][0]; 893 Gamma[3][1] = beta42 - A[3][1]; 894 Gamma[3][2] = beta43 - A[3][2]; 895 Gamma[3][3] = gamma; 896 b[0] = b1; 897 b[1] = b2; 898 b[2] = b3; 899 b[3] = b4; 900 901 /* Construct embedded formula using given e4. We are solving Equation 7.18. */ 902 bm[3] = b[3] - e4 * gamma; /* using definition of E4 */ 903 bm[2] = (p32 - beta4jbetajp * bm[3]) / (beta32 * beta2p); /* fourth row of 7.18 */ 904 bm[1] = (one / two - gamma - beta3p * bm[2] - beta4p * bm[3]) / beta2p; /* second row */ 905 bm[0] = one - bm[1] - bm[2] - bm[3]; /* first row */ 906 907 { 908 const PetscReal misfit = a2 * a2 * bm[1] + a3 * a3 * bm[2] + a4 * a4 * bm[3] - one / three; 909 PetscCheck(PetscAbs(misfit) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_SUP, "Assumptions violated, could not construct a third order embedded method"); 910 } 911 PetscCall(TSRosWRegister(name, 4, 4, &A[0][0], &Gamma[0][0], b, bm, 0, NULL)); 912 PetscFunctionReturn(PETSC_SUCCESS); 913 } 914 915 /* 916 The step completion formula is 917 918 x1 = x0 + b^T Y 919 920 where Y is the multi-vector of stages corrections. This function can be called before or after ts->vec_sol has been 921 updated. Suppose we have a completion formula b and an embedded formula be of different order. We can write 922 923 x1e = x0 + be^T Y 924 = x1 - b^T Y + be^T Y 925 = x1 + (be - b)^T Y 926 927 so we can evaluate the method of different order even after the step has been optimistically completed. 928 */ 929 static PetscErrorCode TSEvaluateStep_RosW(TS ts, PetscInt order, Vec U, PetscBool *done) 930 { 931 TS_RosW *ros = (TS_RosW *)ts->data; 932 RosWTableau tab = ros->tableau; 933 PetscScalar *w = ros->work; 934 PetscInt i; 935 936 PetscFunctionBegin; 937 if (order == tab->order) { 938 if (ros->status == TS_STEP_INCOMPLETE) { /* Use standard completion formula */ 939 PetscCall(VecCopy(ts->vec_sol, U)); 940 for (i = 0; i < tab->s; i++) w[i] = tab->bt[i]; 941 PetscCall(VecMAXPY(U, tab->s, w, ros->Y)); 942 } else PetscCall(VecCopy(ts->vec_sol, U)); 943 if (done) *done = PETSC_TRUE; 944 PetscFunctionReturn(PETSC_SUCCESS); 945 } else if (order == tab->order - 1) { 946 if (!tab->bembedt) goto unavailable; 947 if (ros->status == TS_STEP_INCOMPLETE) { /* Use embedded completion formula */ 948 PetscCall(VecCopy(ts->vec_sol, U)); 949 for (i = 0; i < tab->s; i++) w[i] = tab->bembedt[i]; 950 PetscCall(VecMAXPY(U, tab->s, w, ros->Y)); 951 } else { /* Use rollback-and-recomplete formula (bembedt - bt) */ 952 for (i = 0; i < tab->s; i++) w[i] = tab->bembedt[i] - tab->bt[i]; 953 PetscCall(VecCopy(ts->vec_sol, U)); 954 PetscCall(VecMAXPY(U, tab->s, w, ros->Y)); 955 } 956 if (done) *done = PETSC_TRUE; 957 PetscFunctionReturn(PETSC_SUCCESS); 958 } 959 unavailable: 960 if (done) *done = PETSC_FALSE; 961 else 962 SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Rosenbrock-W '%s' of order %" PetscInt_FMT " cannot evaluate step at order %" PetscInt_FMT ". Consider using -ts_adapt_type none or a different method that has an embedded estimate.", tab->name, 963 tab->order, order); 964 PetscFunctionReturn(PETSC_SUCCESS); 965 } 966 967 static PetscErrorCode TSRollBack_RosW(TS ts) 968 { 969 TS_RosW *ros = (TS_RosW *)ts->data; 970 971 PetscFunctionBegin; 972 PetscCall(VecCopy(ros->vec_sol_prev, ts->vec_sol)); 973 PetscFunctionReturn(PETSC_SUCCESS); 974 } 975 976 static PetscErrorCode TSStep_RosW(TS ts) 977 { 978 TS_RosW *ros = (TS_RosW *)ts->data; 979 RosWTableau tab = ros->tableau; 980 const PetscInt s = tab->s; 981 const PetscReal *At = tab->At, *Gamma = tab->Gamma, *ASum = tab->ASum, *GammaInv = tab->GammaInv; 982 const PetscReal *GammaExplicitCorr = tab->GammaExplicitCorr; 983 const PetscBool *GammaZeroDiag = tab->GammaZeroDiag; 984 PetscScalar *w = ros->work; 985 Vec *Y = ros->Y, Ydot = ros->Ydot, Zdot = ros->Zdot, Zstage = ros->Zstage; 986 SNES snes; 987 TSAdapt adapt; 988 PetscInt i, j, its, lits; 989 PetscInt rejections = 0; 990 PetscBool stageok, accept = PETSC_TRUE; 991 PetscReal next_time_step = ts->time_step; 992 PetscInt lag; 993 994 PetscFunctionBegin; 995 if (!ts->steprollback) PetscCall(VecCopy(ts->vec_sol, ros->vec_sol_prev)); 996 997 ros->status = TS_STEP_INCOMPLETE; 998 while (!ts->reason && ros->status != TS_STEP_COMPLETE) { 999 const PetscReal h = ts->time_step; 1000 for (i = 0; i < s; i++) { 1001 ros->stage_time = ts->ptime + h * ASum[i]; 1002 PetscCall(TSPreStage(ts, ros->stage_time)); 1003 if (GammaZeroDiag[i]) { 1004 ros->stage_explicit = PETSC_TRUE; 1005 ros->scoeff = 1.; 1006 } else { 1007 ros->stage_explicit = PETSC_FALSE; 1008 ros->scoeff = 1. / Gamma[i * s + i]; 1009 } 1010 1011 PetscCall(VecCopy(ts->vec_sol, Zstage)); 1012 for (j = 0; j < i; j++) w[j] = At[i * s + j]; 1013 PetscCall(VecMAXPY(Zstage, i, w, Y)); 1014 1015 for (j = 0; j < i; j++) w[j] = 1. / h * GammaInv[i * s + j]; 1016 PetscCall(VecZeroEntries(Zdot)); 1017 PetscCall(VecMAXPY(Zdot, i, w, Y)); 1018 1019 /* Initial guess taken from last stage */ 1020 PetscCall(VecZeroEntries(Y[i])); 1021 1022 if (!ros->stage_explicit) { 1023 PetscCall(TSGetSNES(ts, &snes)); 1024 if (!ros->recompute_jacobian && !i) { 1025 PetscCall(SNESGetLagJacobian(snes, &lag)); 1026 if (lag == 1) { /* use did not set a nontrivial lag, so lag over all stages */ 1027 PetscCall(SNESSetLagJacobian(snes, -2)); /* Recompute the Jacobian on this solve, but not again for the rest of the stages */ 1028 } 1029 } 1030 PetscCall(SNESSolve(snes, NULL, Y[i])); 1031 if (!ros->recompute_jacobian && i == s - 1 && lag == 1) { PetscCall(SNESSetLagJacobian(snes, lag)); /* Set lag back to 1 so we know user did not set it */ } 1032 PetscCall(SNESGetIterationNumber(snes, &its)); 1033 PetscCall(SNESGetLinearSolveIterations(snes, &lits)); 1034 ts->snes_its += its; 1035 ts->ksp_its += lits; 1036 } else { 1037 Mat J, Jp; 1038 PetscCall(VecZeroEntries(Ydot)); /* Evaluate Y[i]=G(t,Ydot=0,Zstage) */ 1039 PetscCall(TSComputeIFunction(ts, ros->stage_time, Zstage, Ydot, Y[i], PETSC_FALSE)); 1040 PetscCall(VecScale(Y[i], -1.0)); 1041 PetscCall(VecAXPY(Y[i], -1.0, Zdot)); /*Y[i] = F(Zstage)-Zdot[=GammaInv*Y]*/ 1042 1043 PetscCall(VecZeroEntries(Zstage)); /* Zstage = GammaExplicitCorr[i,j] * Y[j] */ 1044 for (j = 0; j < i; j++) w[j] = GammaExplicitCorr[i * s + j]; 1045 PetscCall(VecMAXPY(Zstage, i, w, Y)); 1046 1047 /* Y[i] = Y[i] + Jac*Zstage[=Jac*GammaExplicitCorr[i,j] * Y[j]] */ 1048 PetscCall(TSGetIJacobian(ts, &J, &Jp, NULL, NULL)); 1049 PetscCall(TSComputeIJacobian(ts, ros->stage_time, ts->vec_sol, Ydot, 0, J, Jp, PETSC_FALSE)); 1050 PetscCall(MatMult(J, Zstage, Zdot)); 1051 PetscCall(VecAXPY(Y[i], -1.0, Zdot)); 1052 ts->ksp_its += 1; 1053 1054 PetscCall(VecScale(Y[i], h)); 1055 } 1056 PetscCall(TSPostStage(ts, ros->stage_time, i, Y)); 1057 PetscCall(TSGetAdapt(ts, &adapt)); 1058 PetscCall(TSAdaptCheckStage(adapt, ts, ros->stage_time, Y[i], &stageok)); 1059 if (!stageok) goto reject_step; 1060 } 1061 1062 ros->status = TS_STEP_INCOMPLETE; 1063 PetscCall(TSEvaluateStep_RosW(ts, tab->order, ts->vec_sol, NULL)); 1064 ros->status = TS_STEP_PENDING; 1065 PetscCall(TSGetAdapt(ts, &adapt)); 1066 PetscCall(TSAdaptCandidatesClear(adapt)); 1067 PetscCall(TSAdaptCandidateAdd(adapt, tab->name, tab->order, 1, tab->ccfl, (PetscReal)tab->s, PETSC_TRUE)); 1068 PetscCall(TSAdaptChoose(adapt, ts, ts->time_step, NULL, &next_time_step, &accept)); 1069 ros->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE; 1070 if (!accept) { /* Roll back the current step */ 1071 PetscCall(TSRollBack_RosW(ts)); 1072 ts->time_step = next_time_step; 1073 goto reject_step; 1074 } 1075 1076 ts->ptime += ts->time_step; 1077 ts->time_step = next_time_step; 1078 break; 1079 1080 reject_step: 1081 ts->reject++; 1082 accept = PETSC_FALSE; 1083 if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) { 1084 ts->reason = TS_DIVERGED_STEP_REJECTED; 1085 PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections)); 1086 } 1087 } 1088 PetscFunctionReturn(PETSC_SUCCESS); 1089 } 1090 1091 static PetscErrorCode TSInterpolate_RosW(TS ts, PetscReal itime, Vec U) 1092 { 1093 TS_RosW *ros = (TS_RosW *)ts->data; 1094 PetscInt s = ros->tableau->s, pinterp = ros->tableau->pinterp, i, j; 1095 PetscReal h; 1096 PetscReal tt, t; 1097 PetscScalar *bt; 1098 const PetscReal *Bt = ros->tableau->binterpt; 1099 const PetscReal *GammaInv = ros->tableau->GammaInv; 1100 PetscScalar *w = ros->work; 1101 Vec *Y = ros->Y; 1102 1103 PetscFunctionBegin; 1104 PetscCheck(Bt, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "TSRosW %s does not have an interpolation formula", ros->tableau->name); 1105 1106 switch (ros->status) { 1107 case TS_STEP_INCOMPLETE: 1108 case TS_STEP_PENDING: 1109 h = ts->time_step; 1110 t = (itime - ts->ptime) / h; 1111 break; 1112 case TS_STEP_COMPLETE: 1113 h = ts->ptime - ts->ptime_prev; 1114 t = (itime - ts->ptime) / h + 1; /* In the interval [0,1] */ 1115 break; 1116 default: 1117 SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Invalid TSStepStatus"); 1118 } 1119 PetscCall(PetscMalloc1(s, &bt)); 1120 for (i = 0; i < s; i++) bt[i] = 0; 1121 for (j = 0, tt = t; j < pinterp; j++, tt *= t) { 1122 for (i = 0; i < s; i++) bt[i] += Bt[i * pinterp + j] * tt; 1123 } 1124 1125 /* y(t+tt*h) = y(t) + Sum bt(tt) * GammaInv * Ydot */ 1126 /* U <- 0*/ 1127 PetscCall(VecZeroEntries(U)); 1128 /* U <- Sum bt_i * GammaInv(i,1:i) * Y(1:i) */ 1129 for (j = 0; j < s; j++) w[j] = 0; 1130 for (j = 0; j < s; j++) { 1131 for (i = j; i < s; i++) w[j] += bt[i] * GammaInv[i * s + j]; 1132 } 1133 PetscCall(VecMAXPY(U, i, w, Y)); 1134 /* U <- y(t) + U */ 1135 PetscCall(VecAXPY(U, 1, ros->vec_sol_prev)); 1136 1137 PetscCall(PetscFree(bt)); 1138 PetscFunctionReturn(PETSC_SUCCESS); 1139 } 1140 1141 /*------------------------------------------------------------*/ 1142 1143 static PetscErrorCode TSRosWTableauReset(TS ts) 1144 { 1145 TS_RosW *ros = (TS_RosW *)ts->data; 1146 RosWTableau tab = ros->tableau; 1147 1148 PetscFunctionBegin; 1149 if (!tab) PetscFunctionReturn(PETSC_SUCCESS); 1150 PetscCall(VecDestroyVecs(tab->s, &ros->Y)); 1151 PetscCall(PetscFree(ros->work)); 1152 PetscFunctionReturn(PETSC_SUCCESS); 1153 } 1154 1155 static PetscErrorCode TSReset_RosW(TS ts) 1156 { 1157 TS_RosW *ros = (TS_RosW *)ts->data; 1158 1159 PetscFunctionBegin; 1160 PetscCall(TSRosWTableauReset(ts)); 1161 PetscCall(VecDestroy(&ros->Ydot)); 1162 PetscCall(VecDestroy(&ros->Ystage)); 1163 PetscCall(VecDestroy(&ros->Zdot)); 1164 PetscCall(VecDestroy(&ros->Zstage)); 1165 PetscCall(VecDestroy(&ros->vec_sol_prev)); 1166 PetscFunctionReturn(PETSC_SUCCESS); 1167 } 1168 1169 static PetscErrorCode TSRosWGetVecs(TS ts, DM dm, Vec *Ydot, Vec *Zdot, Vec *Ystage, Vec *Zstage) 1170 { 1171 TS_RosW *rw = (TS_RosW *)ts->data; 1172 1173 PetscFunctionBegin; 1174 if (Ydot) { 1175 if (dm && dm != ts->dm) { 1176 PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Ydot", Ydot)); 1177 } else *Ydot = rw->Ydot; 1178 } 1179 if (Zdot) { 1180 if (dm && dm != ts->dm) { 1181 PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Zdot", Zdot)); 1182 } else *Zdot = rw->Zdot; 1183 } 1184 if (Ystage) { 1185 if (dm && dm != ts->dm) { 1186 PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Ystage", Ystage)); 1187 } else *Ystage = rw->Ystage; 1188 } 1189 if (Zstage) { 1190 if (dm && dm != ts->dm) { 1191 PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Zstage", Zstage)); 1192 } else *Zstage = rw->Zstage; 1193 } 1194 PetscFunctionReturn(PETSC_SUCCESS); 1195 } 1196 1197 static PetscErrorCode TSRosWRestoreVecs(TS ts, DM dm, Vec *Ydot, Vec *Zdot, Vec *Ystage, Vec *Zstage) 1198 { 1199 PetscFunctionBegin; 1200 if (Ydot) { 1201 if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Ydot", Ydot)); 1202 } 1203 if (Zdot) { 1204 if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Zdot", Zdot)); 1205 } 1206 if (Ystage) { 1207 if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Ystage", Ystage)); 1208 } 1209 if (Zstage) { 1210 if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Zstage", Zstage)); 1211 } 1212 PetscFunctionReturn(PETSC_SUCCESS); 1213 } 1214 1215 static PetscErrorCode DMCoarsenHook_TSRosW(DM fine, DM coarse, void *ctx) 1216 { 1217 PetscFunctionBegin; 1218 PetscFunctionReturn(PETSC_SUCCESS); 1219 } 1220 1221 static PetscErrorCode DMRestrictHook_TSRosW(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx) 1222 { 1223 TS ts = (TS)ctx; 1224 Vec Ydot, Zdot, Ystage, Zstage; 1225 Vec Ydotc, Zdotc, Ystagec, Zstagec; 1226 1227 PetscFunctionBegin; 1228 PetscCall(TSRosWGetVecs(ts, fine, &Ydot, &Ystage, &Zdot, &Zstage)); 1229 PetscCall(TSRosWGetVecs(ts, coarse, &Ydotc, &Ystagec, &Zdotc, &Zstagec)); 1230 PetscCall(MatRestrict(restrct, Ydot, Ydotc)); 1231 PetscCall(VecPointwiseMult(Ydotc, rscale, Ydotc)); 1232 PetscCall(MatRestrict(restrct, Ystage, Ystagec)); 1233 PetscCall(VecPointwiseMult(Ystagec, rscale, Ystagec)); 1234 PetscCall(MatRestrict(restrct, Zdot, Zdotc)); 1235 PetscCall(VecPointwiseMult(Zdotc, rscale, Zdotc)); 1236 PetscCall(MatRestrict(restrct, Zstage, Zstagec)); 1237 PetscCall(VecPointwiseMult(Zstagec, rscale, Zstagec)); 1238 PetscCall(TSRosWRestoreVecs(ts, fine, &Ydot, &Ystage, &Zdot, &Zstage)); 1239 PetscCall(TSRosWRestoreVecs(ts, coarse, &Ydotc, &Ystagec, &Zdotc, &Zstagec)); 1240 PetscFunctionReturn(PETSC_SUCCESS); 1241 } 1242 1243 static PetscErrorCode DMSubDomainHook_TSRosW(DM fine, DM coarse, void *ctx) 1244 { 1245 PetscFunctionBegin; 1246 PetscFunctionReturn(PETSC_SUCCESS); 1247 } 1248 1249 static PetscErrorCode DMSubDomainRestrictHook_TSRosW(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx) 1250 { 1251 TS ts = (TS)ctx; 1252 Vec Ydot, Zdot, Ystage, Zstage; 1253 Vec Ydots, Zdots, Ystages, Zstages; 1254 1255 PetscFunctionBegin; 1256 PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage)); 1257 PetscCall(TSRosWGetVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages)); 1258 1259 PetscCall(VecScatterBegin(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD)); 1260 PetscCall(VecScatterEnd(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD)); 1261 1262 PetscCall(VecScatterBegin(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD)); 1263 PetscCall(VecScatterEnd(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD)); 1264 1265 PetscCall(VecScatterBegin(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD)); 1266 PetscCall(VecScatterEnd(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD)); 1267 1268 PetscCall(VecScatterBegin(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD)); 1269 PetscCall(VecScatterEnd(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD)); 1270 1271 PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage)); 1272 PetscCall(TSRosWRestoreVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages)); 1273 PetscFunctionReturn(PETSC_SUCCESS); 1274 } 1275 1276 /* 1277 This defines the nonlinear equation that is to be solved with SNES 1278 G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0 1279 */ 1280 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes, Vec U, Vec F, TS ts) 1281 { 1282 TS_RosW *ros = (TS_RosW *)ts->data; 1283 Vec Ydot, Zdot, Ystage, Zstage; 1284 PetscReal shift = ros->scoeff / ts->time_step; 1285 DM dm, dmsave; 1286 1287 PetscFunctionBegin; 1288 PetscCall(SNESGetDM(snes, &dm)); 1289 PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage)); 1290 PetscCall(VecWAXPY(Ydot, shift, U, Zdot)); /* Ydot = shift*U + Zdot */ 1291 PetscCall(VecWAXPY(Ystage, 1.0, U, Zstage)); /* Ystage = U + Zstage */ 1292 dmsave = ts->dm; 1293 ts->dm = dm; 1294 PetscCall(TSComputeIFunction(ts, ros->stage_time, Ystage, Ydot, F, PETSC_FALSE)); 1295 ts->dm = dmsave; 1296 PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage)); 1297 PetscFunctionReturn(PETSC_SUCCESS); 1298 } 1299 1300 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes, Vec U, Mat A, Mat B, TS ts) 1301 { 1302 TS_RosW *ros = (TS_RosW *)ts->data; 1303 Vec Ydot, Zdot, Ystage, Zstage; 1304 PetscReal shift = ros->scoeff / ts->time_step; 1305 DM dm, dmsave; 1306 1307 PetscFunctionBegin; 1308 /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */ 1309 PetscCall(SNESGetDM(snes, &dm)); 1310 PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage)); 1311 dmsave = ts->dm; 1312 ts->dm = dm; 1313 PetscCall(TSComputeIJacobian(ts, ros->stage_time, Ystage, Ydot, shift, A, B, PETSC_TRUE)); 1314 ts->dm = dmsave; 1315 PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage)); 1316 PetscFunctionReturn(PETSC_SUCCESS); 1317 } 1318 1319 static PetscErrorCode TSRosWTableauSetUp(TS ts) 1320 { 1321 TS_RosW *ros = (TS_RosW *)ts->data; 1322 RosWTableau tab = ros->tableau; 1323 1324 PetscFunctionBegin; 1325 PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &ros->Y)); 1326 PetscCall(PetscMalloc1(tab->s, &ros->work)); 1327 PetscFunctionReturn(PETSC_SUCCESS); 1328 } 1329 1330 static PetscErrorCode TSSetUp_RosW(TS ts) 1331 { 1332 TS_RosW *ros = (TS_RosW *)ts->data; 1333 DM dm; 1334 SNES snes; 1335 TSRHSJacobian rhsjacobian; 1336 1337 PetscFunctionBegin; 1338 PetscCall(TSRosWTableauSetUp(ts)); 1339 PetscCall(VecDuplicate(ts->vec_sol, &ros->Ydot)); 1340 PetscCall(VecDuplicate(ts->vec_sol, &ros->Ystage)); 1341 PetscCall(VecDuplicate(ts->vec_sol, &ros->Zdot)); 1342 PetscCall(VecDuplicate(ts->vec_sol, &ros->Zstage)); 1343 PetscCall(VecDuplicate(ts->vec_sol, &ros->vec_sol_prev)); 1344 PetscCall(TSGetDM(ts, &dm)); 1345 PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSRosW, DMRestrictHook_TSRosW, ts)); 1346 PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSRosW, DMSubDomainRestrictHook_TSRosW, ts)); 1347 /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */ 1348 PetscCall(TSGetSNES(ts, &snes)); 1349 if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESKSPONLY)); 1350 PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL)); 1351 if (rhsjacobian == TSComputeRHSJacobianConstant) { 1352 Mat Amat, Pmat; 1353 1354 /* Set the SNES matrix to be different from the RHS matrix because there is no way to reconstruct shift*M-J */ 1355 PetscCall(SNESGetJacobian(snes, &Amat, &Pmat, NULL, NULL)); 1356 if (Amat && Amat == ts->Arhs) { 1357 if (Amat == Pmat) { 1358 PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat)); 1359 PetscCall(SNESSetJacobian(snes, Amat, Amat, NULL, NULL)); 1360 } else { 1361 PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat)); 1362 PetscCall(SNESSetJacobian(snes, Amat, NULL, NULL, NULL)); 1363 if (Pmat && Pmat == ts->Brhs) { 1364 PetscCall(MatDuplicate(ts->Brhs, MAT_COPY_VALUES, &Pmat)); 1365 PetscCall(SNESSetJacobian(snes, NULL, Pmat, NULL, NULL)); 1366 PetscCall(MatDestroy(&Pmat)); 1367 } 1368 } 1369 PetscCall(MatDestroy(&Amat)); 1370 } 1371 } 1372 PetscFunctionReturn(PETSC_SUCCESS); 1373 } 1374 /*------------------------------------------------------------*/ 1375 1376 static PetscErrorCode TSSetFromOptions_RosW(TS ts, PetscOptionItems *PetscOptionsObject) 1377 { 1378 TS_RosW *ros = (TS_RosW *)ts->data; 1379 SNES snes; 1380 1381 PetscFunctionBegin; 1382 PetscOptionsHeadBegin(PetscOptionsObject, "RosW ODE solver options"); 1383 { 1384 RosWTableauLink link; 1385 PetscInt count, choice; 1386 PetscBool flg; 1387 const char **namelist; 1388 1389 for (link = RosWTableauList, count = 0; link; link = link->next, count++) 1390 ; 1391 PetscCall(PetscMalloc1(count, (char ***)&namelist)); 1392 for (link = RosWTableauList, count = 0; link; link = link->next, count++) namelist[count] = link->tab.name; 1393 PetscCall(PetscOptionsEList("-ts_rosw_type", "Family of Rosenbrock-W method", "TSRosWSetType", (const char *const *)namelist, count, ros->tableau->name, &choice, &flg)); 1394 if (flg) PetscCall(TSRosWSetType(ts, namelist[choice])); 1395 PetscCall(PetscFree(namelist)); 1396 1397 PetscCall(PetscOptionsBool("-ts_rosw_recompute_jacobian", "Recompute the Jacobian at each stage", "TSRosWSetRecomputeJacobian", ros->recompute_jacobian, &ros->recompute_jacobian, NULL)); 1398 } 1399 PetscOptionsHeadEnd(); 1400 /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */ 1401 PetscCall(TSGetSNES(ts, &snes)); 1402 if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESKSPONLY)); 1403 PetscFunctionReturn(PETSC_SUCCESS); 1404 } 1405 1406 static PetscErrorCode TSView_RosW(TS ts, PetscViewer viewer) 1407 { 1408 TS_RosW *ros = (TS_RosW *)ts->data; 1409 PetscBool iascii; 1410 1411 PetscFunctionBegin; 1412 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1413 if (iascii) { 1414 RosWTableau tab = ros->tableau; 1415 TSRosWType rostype; 1416 char buf[512]; 1417 PetscInt i; 1418 PetscReal abscissa[512]; 1419 PetscCall(TSRosWGetType(ts, &rostype)); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, " Rosenbrock-W %s\n", rostype)); 1421 PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, tab->ASum)); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " Abscissa of A = %s\n", buf)); 1423 for (i = 0; i < tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i]; 1424 PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, abscissa)); 1425 PetscCall(PetscViewerASCIIPrintf(viewer, " Abscissa of A+Gamma = %s\n", buf)); 1426 } 1427 PetscFunctionReturn(PETSC_SUCCESS); 1428 } 1429 1430 static PetscErrorCode TSLoad_RosW(TS ts, PetscViewer viewer) 1431 { 1432 SNES snes; 1433 TSAdapt adapt; 1434 1435 PetscFunctionBegin; 1436 PetscCall(TSGetAdapt(ts, &adapt)); 1437 PetscCall(TSAdaptLoad(adapt, viewer)); 1438 PetscCall(TSGetSNES(ts, &snes)); 1439 PetscCall(SNESLoad(snes, viewer)); 1440 /* function and Jacobian context for SNES when used with TS is always ts object */ 1441 PetscCall(SNESSetFunction(snes, NULL, NULL, ts)); 1442 PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, ts)); 1443 PetscFunctionReturn(PETSC_SUCCESS); 1444 } 1445 1446 /*@C 1447 TSRosWSetType - Set the type of Rosenbrock-W, `TSROSW`, scheme 1448 1449 Logically Collective 1450 1451 Input Parameters: 1452 + ts - timestepping context 1453 - roswtype - type of Rosenbrock-W scheme 1454 1455 Level: beginner 1456 1457 .seealso: [](ch_ts), `TSRosWGetType()`, `TSROSW`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`, `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWARK3` 1458 @*/ 1459 PetscErrorCode TSRosWSetType(TS ts, TSRosWType roswtype) 1460 { 1461 PetscFunctionBegin; 1462 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1463 PetscValidCharPointer(roswtype, 2); 1464 PetscTryMethod(ts, "TSRosWSetType_C", (TS, TSRosWType), (ts, roswtype)); 1465 PetscFunctionReturn(PETSC_SUCCESS); 1466 } 1467 1468 /*@C 1469 TSRosWGetType - Get the type of Rosenbrock-W scheme 1470 1471 Logically Collective 1472 1473 Input Parameter: 1474 . ts - timestepping context 1475 1476 Output Parameter: 1477 . rostype - type of Rosenbrock-W scheme 1478 1479 Level: intermediate 1480 1481 .seealso: [](ch_ts), `TSRosWType`, `TSRosWSetType()` 1482 @*/ 1483 PetscErrorCode TSRosWGetType(TS ts, TSRosWType *rostype) 1484 { 1485 PetscFunctionBegin; 1486 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1487 PetscUseMethod(ts, "TSRosWGetType_C", (TS, TSRosWType *), (ts, rostype)); 1488 PetscFunctionReturn(PETSC_SUCCESS); 1489 } 1490 1491 /*@C 1492 TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step. 1493 1494 Logically Collective 1495 1496 Input Parameters: 1497 + ts - timestepping context 1498 - flg - `PETSC_TRUE` to recompute the Jacobian at each stage 1499 1500 Level: intermediate 1501 1502 .seealso: [](ch_ts), `TSRosWType`, `TSRosWGetType()` 1503 @*/ 1504 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts, PetscBool flg) 1505 { 1506 PetscFunctionBegin; 1507 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1508 PetscTryMethod(ts, "TSRosWSetRecomputeJacobian_C", (TS, PetscBool), (ts, flg)); 1509 PetscFunctionReturn(PETSC_SUCCESS); 1510 } 1511 1512 static PetscErrorCode TSRosWGetType_RosW(TS ts, TSRosWType *rostype) 1513 { 1514 TS_RosW *ros = (TS_RosW *)ts->data; 1515 1516 PetscFunctionBegin; 1517 *rostype = ros->tableau->name; 1518 PetscFunctionReturn(PETSC_SUCCESS); 1519 } 1520 1521 static PetscErrorCode TSRosWSetType_RosW(TS ts, TSRosWType rostype) 1522 { 1523 TS_RosW *ros = (TS_RosW *)ts->data; 1524 PetscBool match; 1525 RosWTableauLink link; 1526 1527 PetscFunctionBegin; 1528 if (ros->tableau) { 1529 PetscCall(PetscStrcmp(ros->tableau->name, rostype, &match)); 1530 if (match) PetscFunctionReturn(PETSC_SUCCESS); 1531 } 1532 for (link = RosWTableauList; link; link = link->next) { 1533 PetscCall(PetscStrcmp(link->tab.name, rostype, &match)); 1534 if (match) { 1535 if (ts->setupcalled) PetscCall(TSRosWTableauReset(ts)); 1536 ros->tableau = &link->tab; 1537 if (ts->setupcalled) PetscCall(TSRosWTableauSetUp(ts)); 1538 ts->default_adapt_type = ros->tableau->bembed ? TSADAPTBASIC : TSADAPTNONE; 1539 PetscFunctionReturn(PETSC_SUCCESS); 1540 } 1541 } 1542 SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", rostype); 1543 } 1544 1545 static PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts, PetscBool flg) 1546 { 1547 TS_RosW *ros = (TS_RosW *)ts->data; 1548 1549 PetscFunctionBegin; 1550 ros->recompute_jacobian = flg; 1551 PetscFunctionReturn(PETSC_SUCCESS); 1552 } 1553 1554 static PetscErrorCode TSDestroy_RosW(TS ts) 1555 { 1556 PetscFunctionBegin; 1557 PetscCall(TSReset_RosW(ts)); 1558 if (ts->dm) { 1559 PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSRosW, DMRestrictHook_TSRosW, ts)); 1560 PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSRosW, DMSubDomainRestrictHook_TSRosW, ts)); 1561 } 1562 PetscCall(PetscFree(ts->data)); 1563 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", NULL)); 1564 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", NULL)); 1565 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", NULL)); 1566 PetscFunctionReturn(PETSC_SUCCESS); 1567 } 1568 1569 /* ------------------------------------------------------------ */ 1570 /*MC 1571 TSROSW - ODE solver using Rosenbrock-W schemes 1572 1573 These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly 1574 nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part 1575 of the equation using `TSSetIFunction()` and the non-stiff part with `TSSetRHSFunction()`. 1576 1577 Level: beginner 1578 1579 Notes: 1580 This method currently only works with autonomous ODE and DAE. 1581 1582 Consider trying `TSARKIMEX` if the stiff part is strongly nonlinear. 1583 1584 Since this uses a single linear solve per time-step if you wish to lag the jacobian or preconditioner computation you must use also -snes_lag_jacobian_persists true or -snes_lag_jacobian_preconditioner true 1585 1586 Developer Notes: 1587 Rosenbrock-W methods are typically specified for autonomous ODE 1588 1589 $ udot = f(u) 1590 1591 by the stage equations 1592 1593 $ k_i = h f(u_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j 1594 1595 and step completion formula 1596 1597 $ u_1 = u_0 + sum_j b_j k_j 1598 1599 with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(u) 1600 and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner, 1601 we define new variables for the stage equations 1602 1603 $ y_i = gamma_ij k_j 1604 1605 The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define 1606 1607 $ A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-1} 1608 1609 to rewrite the method as 1610 1611 .vb 1612 [M/(h gamma_ii) - J] y_i = f(u_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j 1613 u_1 = u_0 + sum_j bt_j y_j 1614 .ve 1615 1616 where we have introduced the mass matrix M. Continue by defining 1617 1618 $ ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j 1619 1620 or, more compactly in tensor notation 1621 1622 $ Ydot = 1/h (Gamma^{-1} \otimes I) Y . 1623 1624 Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current 1625 stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the 1626 equation 1627 1628 $ g(u_0 + sum_j a_ij y_j + y_i, ydot_i) = 0 1629 1630 with initial guess y_i = 0. 1631 1632 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSRosWSetType()`, `TSRosWRegister()`, `TSROSWTHETA1`, `TSROSWTHETA2`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`, 1633 `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSWVELDD4`, `TSROSW4L`, `TSType` 1634 M*/ 1635 PETSC_EXTERN PetscErrorCode TSCreate_RosW(TS ts) 1636 { 1637 TS_RosW *ros; 1638 1639 PetscFunctionBegin; 1640 PetscCall(TSRosWInitializePackage()); 1641 1642 ts->ops->reset = TSReset_RosW; 1643 ts->ops->destroy = TSDestroy_RosW; 1644 ts->ops->view = TSView_RosW; 1645 ts->ops->load = TSLoad_RosW; 1646 ts->ops->setup = TSSetUp_RosW; 1647 ts->ops->step = TSStep_RosW; 1648 ts->ops->interpolate = TSInterpolate_RosW; 1649 ts->ops->evaluatestep = TSEvaluateStep_RosW; 1650 ts->ops->rollback = TSRollBack_RosW; 1651 ts->ops->setfromoptions = TSSetFromOptions_RosW; 1652 ts->ops->snesfunction = SNESTSFormFunction_RosW; 1653 ts->ops->snesjacobian = SNESTSFormJacobian_RosW; 1654 1655 ts->usessnes = PETSC_TRUE; 1656 1657 PetscCall(PetscNew(&ros)); 1658 ts->data = (void *)ros; 1659 1660 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", TSRosWGetType_RosW)); 1661 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", TSRosWSetType_RosW)); 1662 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", TSRosWSetRecomputeJacobian_RosW)); 1663 1664 PetscCall(TSRosWSetType(ts, TSRosWDefault)); 1665 PetscFunctionReturn(PETSC_SUCCESS); 1666 } 1667