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