Actual source code: rosw.c

  1: /*
  2:   Code for timestepping with Rosenbrock W methods

  4:   Notes:
  5:   The general system is written as

  7:   F(t,U,Udot) = G(t,U)

  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.

 12: */
 13: #include <petsc/private/tsimpl.h>
 14: #include <petscdm.h>

 16: #include <petsc/private/kernels/blockinvert.h>

 18: static TSRosWType TSRosWDefault = TSROSWRA34PW2;
 19: static PetscBool  TSRosWRegisterAllCalled;
 20: static PetscBool  TSRosWPackageInitialized;

 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;

 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;

 66: /*MC
 67:      TSROSWTHETA1 - One stage first order L-stable Rosenbrock-W scheme (aka theta method).

 69:      Only an approximate Jacobian is needed.

 71:      Level: intermediate

 73: .seealso: [](ch_ts), `TSROSW`
 74: M*/

 76: /*MC
 77:      TSROSWTHETA2 - One stage second order A-stable Rosenbrock-W scheme (aka theta method).

 79:      Only an approximate Jacobian is needed.

 81:      Level: intermediate

 83: .seealso: [](ch_ts), `TSROSW`
 84: M*/

 86: /*MC
 87:      TSROSW2M - Two stage second order L-stable Rosenbrock-W scheme.

 89:      Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2P.

 91:      Level: intermediate

 93: .seealso: [](ch_ts), `TSROSW`
 94: M*/

 96: /*MC
 97:      TSROSW2P - Two stage second order L-stable Rosenbrock-W scheme.

 99:      Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2M.

101:      Level: intermediate

103: .seealso: [](ch_ts), `TSROSW`
104: M*/

106: /*MC
107:      TSROSWRA3PW - Three stage third order Rosenbrock-W scheme for PDAE of index 1 {cite}`rang_2005`

109:      Only an approximate Jacobian is needed. By default, it is only recomputed once per step.

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.

113:      Level: intermediate

115: .seealso: [](ch_ts), `TSROSW`
116: M*/

118: /*MC
119:      TSROSWRA34PW2 - Four stage third order L-stable Rosenbrock-W scheme for PDAE of index 1 {cite}`rang_2005`.

121:      Only an approximate Jacobian is needed. By default, it is only recomputed once per step.

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.

125:      Level: intermediate

127: .seealso: [](ch_ts), `TSROSW`
128: M*/

130: /*MC
131:      TSROSWRODAS3 - Four stage third order L-stable Rosenbrock scheme {cite}`sandu_1997`

133:      By default, the Jacobian is only recomputed once per step.

135:      Both the third order and embedded second order methods are stiffly accurate and L-stable.

137:      Level: intermediate

139: .seealso: [](ch_ts), `TSROSW`, `TSROSWSANDU3`
140: M*/

142: /*MC
143:      TSROSWSANDU3 - Three stage third order L-stable Rosenbrock scheme {cite}`sandu_1997`

145:      By default, the Jacobian is only recomputed once per step.

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`.

152:      Level: intermediate

154: .seealso: [](ch_ts), `TSROSW`, `TSROSWRODAS3`
155: M*/

157: /*MC
158:      TSROSWASSP3P3S1C - A-stable Rosenbrock-W method with SSP explicit part, third order, three stages

160:      By default, the Jacobian is only recomputed once per step.

162:      A-stable SPP explicit order 3, 3 stages, CFL 1 (eff = 1/3)

164:      Level: intermediate

166: .seealso: [](ch_ts), `TSROSW`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `SSP`
167: M*/

169: /*MC
170:      TSROSWLASSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, four stages

172:      By default, the Jacobian is only recomputed once per step.

174:      L-stable (A-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2)

176:      Level: intermediate

178: .seealso: [](ch_ts), `TSROSW`, `TSROSWASSP3P3S1C`, `TSROSWLLSSP3P4S2C`, `TSSSP`
179: M*/

181: /*MC
182:      TSROSWLLSSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, four stages

184:      By default, the Jacobian is only recomputed once per step.

186:      L-stable (L-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2)

188:      Level: intermediate

190: .seealso: [](ch_ts), `TSROSW`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSSSP`
191: M*/

193: /*MC
194:      TSROSWGRK4T - four stage, fourth order Rosenbrock (not W) method from Kaps and Rentrop {cite}`kaps1979generalized`

196:      By default, the Jacobian is only recomputed once per step.

198:      A(89.3 degrees)-stable, |R(infty)| = 0.454.

200:      This method does not provide a dense output formula.

202:      Level: intermediate

204:      Note:
205:      See Section 4 Table 7.2 in {cite}`wanner1996solving`

207: .seealso: [](ch_ts), `TSROSW`, `TSROSWSHAMP4`, `TSROSWVELDD4`, `TSROSW4L`
208: M*/

210: /*MC
211:      TSROSWSHAMP4 - four stage, fourth order Rosenbrock (not W) method from Shampine {cite}`shampine1982implementation`

213:      By default, the Jacobian is only recomputed once per step.

215:      A-stable, |R(infty)| = 1/3.

217:      This method does not provide a dense output formula.

219:      Level: intermediate

221:      Note:
222:      See Section 4 Table 7.2 in in {cite}`wanner1996solving`

224: .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWVELDD4`, `TSROSW4L`
225: M*/

227: /*MC
228:      TSROSWVELDD4 - four stage, fourth order Rosenbrock (not W) method from van Veldhuizen {cite}`veldhuizen1984d`

230:      By default, the Jacobian is only recomputed once per step.

232:      A(89.5 degrees)-stable, |R(infty)| = 0.24.

234:      This method does not provide a dense output formula.

236:      Level: intermediate

238:      Note:
239:      See Section 4 Table 7.2 in {cite}`wanner1996solving`

241: .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSW4L`
242: M*/

244: /*MC
245:      TSROSW4L - four stage, fourth order Rosenbrock (not W) method

247:      By default, the Jacobian is only recomputed once per step.

249:      A-stable and L-stable

251:      This method does not provide a dense output formula.

253:      Level: intermediate

255:      Note:
256:      See Section 4 Table 7.2 in in {cite}`wanner1996solving`

258: .seealso: [](ch_ts), `TSROSW`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSW4L`
259: M*/

261: /*@C
262:   TSRosWRegisterAll - Registers all of the Rosenbrock-W methods in `TSROSW`

264:   Not Collective, but should be called by all MPI processes which will need the schemes to be registered

266:   Level: advanced

268: .seealso: [](ch_ts), `TSROSW`, `TSRosWRegisterDestroy()`
269: @*/
270: PetscErrorCode TSRosWRegisterAll(void)
271: {
272:   PetscFunctionBegin;
273:   if (TSRosWRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
274:   TSRosWRegisterAllCalled = PETSC_TRUE;

276:   {
277:     const PetscReal A        = 0;
278:     const PetscReal Gamma    = 1;
279:     const PetscReal b        = 1;
280:     const PetscReal binterpt = 1;

282:     PetscCall(TSRosWRegister(TSROSWTHETA1, 1, 1, &A, &Gamma, &b, NULL, 1, &binterpt));
283:   }

285:   {
286:     const PetscReal A        = 0;
287:     const PetscReal Gamma    = 0.5;
288:     const PetscReal b        = 1;
289:     const PetscReal binterpt = 1;

291:     PetscCall(TSRosWRegister(TSROSWTHETA2, 2, 1, &A, &Gamma, &b, NULL, 1, &binterpt));
292:   }

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;

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;

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};

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;

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};

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;

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};

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};

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;

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];

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;

462:     PetscCall(TSRosWRegister(TSROSWASSP3P3S1C, 3, 3, &A[0][0], &Gamma[0][0], b, b2, 2, &binterpt[0][0]));
463:   }

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];

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.;

495:     PetscCall(TSRosWRegister(TSROSWLASSP3P4S2C, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0]));
496:   }

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];

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;

528:     PetscCall(TSRosWRegister(TSROSWLLSSP3P4S2C, 3, 4, &A[0][0], &Gamma[0][0], b, b2, 3, &binterpt[0][0]));
529:   }

531:   {
532:     PetscReal A[4][4], Gamma[4][4], b[4], b2[4];
533:     PetscReal binterpt[4][3];

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;

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;

569:     b[0] = 0.1876410243467238251612921333138006734899663569186926;
570:     b[1] = -0.5952974735769549480478230473706443582188442040780541;
571:     b[2] = 0.9717899277217721234705114616271378792182450260943198;
572:     b[3] = 0.4358665215084589994160194475295062513822671686978816;

574:     b2[0] = 0.2147402862233891404862383521089097657790734483804460;
575:     b2[1] = -0.4851622638849390928209050538171743017757490232519684;
576:     b2[2] = 0.8687250025203875511662123688667549217531982787600080;
577:     b2[3] = 0.4016969751411624011684543450940068201770721128357014;

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;

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: }

601: /*@C
602:   TSRosWRegisterDestroy - Frees the list of schemes that were registered by `TSRosWRegister()`.

604:   Not Collective

606:   Level: advanced

608: .seealso: [](ch_ts), `TSRosWRegister()`, `TSRosWRegisterAll()`
609: @*/
610: PetscErrorCode TSRosWRegisterDestroy(void)
611: {
612:   RosWTableauLink link;

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: }

629: /*@C
630:   TSRosWInitializePackage - This function initializes everything in the `TSROSW` package. It is called
631:   from `TSInitializePackage()`.

633:   Level: developer

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: }

647: /*@C
648:   TSRosWFinalizePackage - This function destroys everything in the `TSROSW` package. It is
649:   called from `PetscFinalize()`.

651:   Level: developer

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: }

663: /*@C
664:   TSRosWRegister - register a `TSROSW`, Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation

666:   Not Collective, but the same schemes should be registered on all processes on which they will be used

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)

679:   Level: advanced

681:   Note:
682:   Several Rosenbrock W methods are provided, this function is only needed to create new methods.

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;

693:   PetscFunctionBegin;
694:   PetscAssertPointer(name, 1);
695:   PetscAssertPointer(A, 4);
696:   PetscAssertPointer(Gamma, 5);
697:   PetscAssertPointer(b, 6);
698:   if (bembed) PetscAssertPointer(bembed, 7);

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:   }

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));

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:   }

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 */

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: }

795: /*@C
796:   TSRosWRegisterRos4 - register a fourth order Rosenbrock scheme by providing parameter choices

798:   Not Collective, but the same schemes should be registered on all processes on which they will be used

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

808:   Level: developer

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.

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];

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 */

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]);

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]);

870:   /* Step 4: back-substitute */
871:   beta32 = beta32beta2p / beta2p;
872:   beta42 = (beta4jbetajp - beta43 * beta3p) / beta2p;

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;

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;

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 */

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: }

930: /*
931:  The step completion formula is

933:  x1 = x0 + b^T Y

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

938:  x1e = x0 + be^T Y
939:      = x1 - b^T Y + be^T Y
940:      = x1 + (be - b)^T Y

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;

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: }

982: static PetscErrorCode TSRollBack_RosW(TS ts)
983: {
984:   TS_RosW *ros = (TS_RosW *)ts->data;

986:   PetscFunctionBegin;
987:   PetscCall(VecCopy(ros->vec_sol_prev, ts->vec_sol));
988:   PetscFunctionReturn(PETSC_SUCCESS);
989: }

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;

1009:   PetscFunctionBegin;
1010:   if (!ts->steprollback) PetscCall(VecCopy(ts->vec_sol, ros->vec_sol_prev));

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:       }

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));

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));

1034:       /* Initial guess taken from last stage */
1035:       PetscCall(VecZeroEntries(Y[i]));

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]*/

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));

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;

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:     }

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:     }

1091:     ts->ptime += ts->time_step;
1092:     ts->time_step = next_time_step;
1093:     break;

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: }

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;

1118:   PetscFunctionBegin;
1119:   PetscCheck(Bt, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "TSRosW %s does not have an interpolation formula", ros->tableau->name);

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:   }

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));

1152:   PetscCall(PetscFree(bt));
1153:   PetscFunctionReturn(PETSC_SUCCESS);
1154: }

1156: /*------------------------------------------------------------*/

1158: static PetscErrorCode TSRosWTableauReset(TS ts)
1159: {
1160:   TS_RosW    *ros = (TS_RosW *)ts->data;
1161:   RosWTableau tab = ros->tableau;

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: }

1170: static PetscErrorCode TSReset_RosW(TS ts)
1171: {
1172:   TS_RosW *ros = (TS_RosW *)ts->data;

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: }

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;

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: }

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: }

1230: static PetscErrorCode DMCoarsenHook_TSRosW(DM fine, DM coarse, void *ctx)
1231: {
1232:   PetscFunctionBegin;
1233:   PetscFunctionReturn(PETSC_SUCCESS);
1234: }

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;

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: }

1258: static PetscErrorCode DMSubDomainHook_TSRosW(DM fine, DM coarse, void *ctx)
1259: {
1260:   PetscFunctionBegin;
1261:   PetscFunctionReturn(PETSC_SUCCESS);
1262: }

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;

1270:   PetscFunctionBegin;
1271:   PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage));
1272:   PetscCall(TSRosWGetVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages));

1274:   PetscCall(VecScatterBegin(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD));
1275:   PetscCall(VecScatterEnd(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD));

1277:   PetscCall(VecScatterBegin(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD));
1278:   PetscCall(VecScatterEnd(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD));

1280:   PetscCall(VecScatterBegin(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD));
1281:   PetscCall(VecScatterEnd(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD));

1283:   PetscCall(VecScatterBegin(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD));
1284:   PetscCall(VecScatterEnd(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD));

1286:   PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage));
1287:   PetscCall(TSRosWRestoreVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages));
1288:   PetscFunctionReturn(PETSC_SUCCESS);
1289: }

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;

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: }

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;

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: }

1334: static PetscErrorCode TSRosWTableauSetUp(TS ts)
1335: {
1336:   TS_RosW    *ros = (TS_RosW *)ts->data;
1337:   RosWTableau tab = ros->tableau;

1339:   PetscFunctionBegin;
1340:   PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &ros->Y));
1341:   PetscCall(PetscMalloc1(tab->s, &ros->work));
1342:   PetscFunctionReturn(PETSC_SUCCESS);
1343: }

1345: static PetscErrorCode TSSetUp_RosW(TS ts)
1346: {
1347:   TS_RosW      *ros = (TS_RosW *)ts->data;
1348:   DM            dm;
1349:   SNES          snes;
1350:   TSRHSJacobian rhsjacobian;

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;

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: /*------------------------------------------------------------*/

1391: static PetscErrorCode TSSetFromOptions_RosW(TS ts, PetscOptionItems *PetscOptionsObject)
1392: {
1393:   TS_RosW *ros = (TS_RosW *)ts->data;
1394:   SNES     snes;

1396:   PetscFunctionBegin;
1397:   PetscOptionsHeadBegin(PetscOptionsObject, "RosW ODE solver options");
1398:   {
1399:     RosWTableauLink link;
1400:     PetscInt        count, choice;
1401:     PetscBool       flg;
1402:     const char    **namelist;

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));

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: }

1421: static PetscErrorCode TSView_RosW(TS ts, PetscViewer viewer)
1422: {
1423:   TS_RosW  *ros = (TS_RosW *)ts->data;
1424:   PetscBool iascii;

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: }

1445: static PetscErrorCode TSLoad_RosW(TS ts, PetscViewer viewer)
1446: {
1447:   SNES    snes;
1448:   TSAdapt adapt;

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: }

1461: /*@C
1462:   TSRosWSetType - Set the type of Rosenbrock-W, `TSROSW`, scheme

1464:   Logically Collective

1466:   Input Parameters:
1467: + ts       - timestepping context
1468: - roswtype - type of Rosenbrock-W scheme

1470:   Level: beginner

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;
1478:   PetscAssertPointer(roswtype, 2);
1479:   PetscTryMethod(ts, "TSRosWSetType_C", (TS, TSRosWType), (ts, roswtype));
1480:   PetscFunctionReturn(PETSC_SUCCESS);
1481: }

1483: /*@C
1484:   TSRosWGetType - Get the type of Rosenbrock-W scheme

1486:   Logically Collective

1488:   Input Parameter:
1489: . ts - timestepping context

1491:   Output Parameter:
1492: . rostype - type of Rosenbrock-W scheme

1494:   Level: intermediate

1496: .seealso: [](ch_ts), `TSRosWType`, `TSRosWSetType()`
1497: @*/
1498: PetscErrorCode TSRosWGetType(TS ts, TSRosWType *rostype)
1499: {
1500:   PetscFunctionBegin;
1502:   PetscUseMethod(ts, "TSRosWGetType_C", (TS, TSRosWType *), (ts, rostype));
1503:   PetscFunctionReturn(PETSC_SUCCESS);
1504: }

1506: /*@C
1507:   TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step.

1509:   Logically Collective

1511:   Input Parameters:
1512: + ts  - timestepping context
1513: - flg - `PETSC_TRUE` to recompute the Jacobian at each stage

1515:   Level: intermediate

1517: .seealso: [](ch_ts), `TSRosWType`, `TSRosWGetType()`
1518: @*/
1519: PetscErrorCode TSRosWSetRecomputeJacobian(TS ts, PetscBool flg)
1520: {
1521:   PetscFunctionBegin;
1523:   PetscTryMethod(ts, "TSRosWSetRecomputeJacobian_C", (TS, PetscBool), (ts, flg));
1524:   PetscFunctionReturn(PETSC_SUCCESS);
1525: }

1527: static PetscErrorCode TSRosWGetType_RosW(TS ts, TSRosWType *rostype)
1528: {
1529:   TS_RosW *ros = (TS_RosW *)ts->data;

1531:   PetscFunctionBegin;
1532:   *rostype = ros->tableau->name;
1533:   PetscFunctionReturn(PETSC_SUCCESS);
1534: }

1536: static PetscErrorCode TSRosWSetType_RosW(TS ts, TSRosWType rostype)
1537: {
1538:   TS_RosW        *ros = (TS_RosW *)ts->data;
1539:   PetscBool       match;
1540:   RosWTableauLink link;

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: }

1560: static PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts, PetscBool flg)
1561: {
1562:   TS_RosW *ros = (TS_RosW *)ts->data;

1564:   PetscFunctionBegin;
1565:   ros->recompute_jacobian = flg;
1566:   PetscFunctionReturn(PETSC_SUCCESS);
1567: }

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: }

1584: /* ------------------------------------------------------------ */
1585: /*MC
1586:       TSROSW - ODE solver using Rosenbrock-W schemes

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()`.

1592:   Level: beginner

1594:   Notes:
1595:   This method currently only works with autonomous ODE and DAE.

1597:   Consider trying `TSARKIMEX` if the stiff part is strongly nonlinear.

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

1601:   Developer Notes:
1602:   Rosenbrock-W methods are typically specified for autonomous ODE

1604: $  udot = f(u)

1606:   by the stage equations

1608: $  k_i = h f(u_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j

1610:   and step completion formula

1612: $  u_1 = u_0 + sum_j b_j k_j

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

1618: $  y_i = gamma_ij k_j

1620:   The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define

1622: $  A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-1}

1624:   to rewrite the method as

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

1631:    where we have introduced the mass matrix M. Continue by defining

1633: $  ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j

1635:    or, more compactly in tensor notation

1637: $  Ydot = 1/h (Gamma^{-1} \otimes I) Y .

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

1643: $  g(u_0 + sum_j a_ij y_j + y_i, ydot_i) = 0

1645:    with initial guess y_i = 0.

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;

1654:   PetscFunctionBegin;
1655:   PetscCall(TSRosWInitializePackage());

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;

1670:   ts->usessnes = PETSC_TRUE;

1672:   PetscCall(PetscNew(&ros));
1673:   ts->data = (void *)ros;

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));

1679:   PetscCall(TSRosWSetType(ts, TSRosWDefault));
1680:   PetscFunctionReturn(PETSC_SUCCESS);
1681: }