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 ; 1406 PetscCall(PetscMalloc1(count, (char ***)&namelist)); 1407 for (link = RosWTableauList, count = 0; link; link = link->next, count++) namelist[count] = link->tab.name; 1408 PetscCall(PetscOptionsEList("-ts_rosw_type", "Family of Rosenbrock-W method", "TSRosWSetType", (const char *const *)namelist, count, ros->tableau->name, &choice, &flg)); 1409 if (flg) PetscCall(TSRosWSetType(ts, namelist[choice])); 1410 PetscCall(PetscFree(namelist)); 1411 1412 PetscCall(PetscOptionsBool("-ts_rosw_recompute_jacobian", "Recompute the Jacobian at each stage", "TSRosWSetRecomputeJacobian", ros->recompute_jacobian, &ros->recompute_jacobian, NULL)); 1413 } 1414 PetscOptionsHeadEnd(); 1415 /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */ 1416 PetscCall(TSGetSNES(ts, &snes)); 1417 if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESKSPONLY)); 1418 PetscFunctionReturn(PETSC_SUCCESS); 1419 } 1420 1421 static PetscErrorCode TSView_RosW(TS ts, PetscViewer viewer) 1422 { 1423 TS_RosW *ros = (TS_RosW *)ts->data; 1424 PetscBool iascii; 1425 1426 PetscFunctionBegin; 1427 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1428 if (iascii) { 1429 RosWTableau tab = ros->tableau; 1430 TSRosWType rostype; 1431 char buf[512]; 1432 PetscInt i; 1433 PetscReal abscissa[512]; 1434 PetscCall(TSRosWGetType(ts, &rostype)); 1435 PetscCall(PetscViewerASCIIPrintf(viewer, " Rosenbrock-W %s\n", rostype)); 1436 PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, tab->ASum)); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, " Abscissa of A = %s\n", buf)); 1438 for (i = 0; i < tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i]; 1439 PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, abscissa)); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, " Abscissa of A+Gamma = %s\n", buf)); 1441 } 1442 PetscFunctionReturn(PETSC_SUCCESS); 1443 } 1444 1445 static PetscErrorCode TSLoad_RosW(TS ts, PetscViewer viewer) 1446 { 1447 SNES snes; 1448 TSAdapt adapt; 1449 1450 PetscFunctionBegin; 1451 PetscCall(TSGetAdapt(ts, &adapt)); 1452 PetscCall(TSAdaptLoad(adapt, viewer)); 1453 PetscCall(TSGetSNES(ts, &snes)); 1454 PetscCall(SNESLoad(snes, viewer)); 1455 /* function and Jacobian context for SNES when used with TS is always ts object */ 1456 PetscCall(SNESSetFunction(snes, NULL, NULL, ts)); 1457 PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, ts)); 1458 PetscFunctionReturn(PETSC_SUCCESS); 1459 } 1460 1461 /*@C 1462 TSRosWSetType - Set the type of Rosenbrock-W, `TSROSW`, scheme 1463 1464 Logically Collective 1465 1466 Input Parameters: 1467 + ts - timestepping context 1468 - roswtype - type of Rosenbrock-W scheme 1469 1470 Level: beginner 1471 1472 .seealso: [](ch_ts), `TSRosWGetType()`, `TSROSW`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`, `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWARK3` 1473 @*/ 1474 PetscErrorCode TSRosWSetType(TS ts, TSRosWType roswtype) 1475 { 1476 PetscFunctionBegin; 1477 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1478 PetscAssertPointer(roswtype, 2); 1479 PetscTryMethod(ts, "TSRosWSetType_C", (TS, TSRosWType), (ts, roswtype)); 1480 PetscFunctionReturn(PETSC_SUCCESS); 1481 } 1482 1483 /*@C 1484 TSRosWGetType - Get the type of Rosenbrock-W scheme 1485 1486 Logically Collective 1487 1488 Input Parameter: 1489 . ts - timestepping context 1490 1491 Output Parameter: 1492 . rostype - type of Rosenbrock-W scheme 1493 1494 Level: intermediate 1495 1496 .seealso: [](ch_ts), `TSRosWType`, `TSRosWSetType()` 1497 @*/ 1498 PetscErrorCode TSRosWGetType(TS ts, TSRosWType *rostype) 1499 { 1500 PetscFunctionBegin; 1501 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1502 PetscUseMethod(ts, "TSRosWGetType_C", (TS, TSRosWType *), (ts, rostype)); 1503 PetscFunctionReturn(PETSC_SUCCESS); 1504 } 1505 1506 /*@C 1507 TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step. 1508 1509 Logically Collective 1510 1511 Input Parameters: 1512 + ts - timestepping context 1513 - flg - `PETSC_TRUE` to recompute the Jacobian at each stage 1514 1515 Level: intermediate 1516 1517 .seealso: [](ch_ts), `TSRosWType`, `TSRosWGetType()` 1518 @*/ 1519 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts, PetscBool flg) 1520 { 1521 PetscFunctionBegin; 1522 PetscValidHeaderSpecific(ts, TS_CLASSID, 1); 1523 PetscTryMethod(ts, "TSRosWSetRecomputeJacobian_C", (TS, PetscBool), (ts, flg)); 1524 PetscFunctionReturn(PETSC_SUCCESS); 1525 } 1526 1527 static PetscErrorCode TSRosWGetType_RosW(TS ts, TSRosWType *rostype) 1528 { 1529 TS_RosW *ros = (TS_RosW *)ts->data; 1530 1531 PetscFunctionBegin; 1532 *rostype = ros->tableau->name; 1533 PetscFunctionReturn(PETSC_SUCCESS); 1534 } 1535 1536 static PetscErrorCode TSRosWSetType_RosW(TS ts, TSRosWType rostype) 1537 { 1538 TS_RosW *ros = (TS_RosW *)ts->data; 1539 PetscBool match; 1540 RosWTableauLink link; 1541 1542 PetscFunctionBegin; 1543 if (ros->tableau) { 1544 PetscCall(PetscStrcmp(ros->tableau->name, rostype, &match)); 1545 if (match) PetscFunctionReturn(PETSC_SUCCESS); 1546 } 1547 for (link = RosWTableauList; link; link = link->next) { 1548 PetscCall(PetscStrcmp(link->tab.name, rostype, &match)); 1549 if (match) { 1550 if (ts->setupcalled) PetscCall(TSRosWTableauReset(ts)); 1551 ros->tableau = &link->tab; 1552 if (ts->setupcalled) PetscCall(TSRosWTableauSetUp(ts)); 1553 ts->default_adapt_type = ros->tableau->bembed ? TSADAPTBASIC : TSADAPTNONE; 1554 PetscFunctionReturn(PETSC_SUCCESS); 1555 } 1556 } 1557 SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", rostype); 1558 } 1559 1560 static PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts, PetscBool flg) 1561 { 1562 TS_RosW *ros = (TS_RosW *)ts->data; 1563 1564 PetscFunctionBegin; 1565 ros->recompute_jacobian = flg; 1566 PetscFunctionReturn(PETSC_SUCCESS); 1567 } 1568 1569 static PetscErrorCode TSDestroy_RosW(TS ts) 1570 { 1571 PetscFunctionBegin; 1572 PetscCall(TSReset_RosW(ts)); 1573 if (ts->dm) { 1574 PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSRosW, DMRestrictHook_TSRosW, ts)); 1575 PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSRosW, DMSubDomainRestrictHook_TSRosW, ts)); 1576 } 1577 PetscCall(PetscFree(ts->data)); 1578 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", NULL)); 1579 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", NULL)); 1580 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", NULL)); 1581 PetscFunctionReturn(PETSC_SUCCESS); 1582 } 1583 1584 /* ------------------------------------------------------------ */ 1585 /*MC 1586 TSROSW - ODE solver using Rosenbrock-W schemes 1587 1588 These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly 1589 nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part 1590 of the equation using `TSSetIFunction()` and the non-stiff part with `TSSetRHSFunction()`. 1591 1592 Level: beginner 1593 1594 Notes: 1595 This method currently only works with autonomous ODE and DAE. 1596 1597 Consider trying `TSARKIMEX` if the stiff part is strongly nonlinear. 1598 1599 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 1600 1601 Developer Notes: 1602 Rosenbrock-W methods are typically specified for autonomous ODE 1603 1604 $ udot = f(u) 1605 1606 by the stage equations 1607 1608 $ k_i = h f(u_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j 1609 1610 and step completion formula 1611 1612 $ u_1 = u_0 + sum_j b_j k_j 1613 1614 with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(u) 1615 and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner, 1616 we define new variables for the stage equations 1617 1618 $ y_i = gamma_ij k_j 1619 1620 The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define 1621 1622 $ A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-1} 1623 1624 to rewrite the method as 1625 1626 .vb 1627 [M/(h gamma_ii) - J] y_i = f(u_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j 1628 u_1 = u_0 + sum_j bt_j y_j 1629 .ve 1630 1631 where we have introduced the mass matrix M. Continue by defining 1632 1633 $ ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j 1634 1635 or, more compactly in tensor notation 1636 1637 $ Ydot = 1/h (Gamma^{-1} \otimes I) Y . 1638 1639 Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current 1640 stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the 1641 equation 1642 1643 $ g(u_0 + sum_j a_ij y_j + y_i, ydot_i) = 0 1644 1645 with initial guess y_i = 0. 1646 1647 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSRosWSetType()`, `TSRosWRegister()`, `TSROSWTHETA1`, `TSROSWTHETA2`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`, 1648 `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSWVELDD4`, `TSROSW4L`, `TSType` 1649 M*/ 1650 PETSC_EXTERN PetscErrorCode TSCreate_RosW(TS ts) 1651 { 1652 TS_RosW *ros; 1653 1654 PetscFunctionBegin; 1655 PetscCall(TSRosWInitializePackage()); 1656 1657 ts->ops->reset = TSReset_RosW; 1658 ts->ops->destroy = TSDestroy_RosW; 1659 ts->ops->view = TSView_RosW; 1660 ts->ops->load = TSLoad_RosW; 1661 ts->ops->setup = TSSetUp_RosW; 1662 ts->ops->step = TSStep_RosW; 1663 ts->ops->interpolate = TSInterpolate_RosW; 1664 ts->ops->evaluatestep = TSEvaluateStep_RosW; 1665 ts->ops->rollback = TSRollBack_RosW; 1666 ts->ops->setfromoptions = TSSetFromOptions_RosW; 1667 ts->ops->snesfunction = SNESTSFormFunction_RosW; 1668 ts->ops->snesjacobian = SNESTSFormJacobian_RosW; 1669 1670 ts->usessnes = PETSC_TRUE; 1671 1672 PetscCall(PetscNew(&ros)); 1673 ts->data = (void *)ros; 1674 1675 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", TSRosWGetType_RosW)); 1676 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", TSRosWSetType_RosW)); 1677 PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", TSRosWSetRecomputeJacobian_RosW)); 1678 1679 PetscCall(TSRosWSetType(ts, TSRosWDefault)); 1680 PetscFunctionReturn(PETSC_SUCCESS); 1681 } 1682