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