xref: /petsc/src/ts/impls/rosw/rosw.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc) !
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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_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: [](chapter_ts), `TSROSW`, `TSRosWRegisterDestroy()`
301 @*/
302 PetscErrorCode TSRosWRegisterAll(void)
303 {
304   PetscFunctionBegin;
305   if (TSRosWRegisterAllCalled) PetscFunctionReturn(0);
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(0);
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: [](chapter_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(0);
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: [](chapter_ts), `TSROSW`, `PetscInitialize()`, `TSRosWFinalizePackage()`
621 @*/
622 PetscErrorCode TSRosWInitializePackage(void)
623 {
624   PetscFunctionBegin;
625   if (TSRosWPackageInitialized) PetscFunctionReturn(0);
626   TSRosWPackageInitialized = PETSC_TRUE;
627   PetscCall(TSRosWRegisterAll());
628   PetscCall(PetscRegisterFinalize(TSRosWFinalizePackage));
629   PetscFunctionReturn(0);
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: [](chapter_ts), `TSROSW`, `PetscFinalize()`, `TSRosWInitializePackage()`
639 @*/
640 PetscErrorCode TSRosWFinalizePackage(void)
641 {
642   PetscFunctionBegin;
643   TSRosWPackageInitialized = PETSC_FALSE;
644   PetscCall(TSRosWRegisterDestroy());
645   PetscFunctionReturn(0);
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: [](chapter_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(0);
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 .  beta43 - design parameter or PETSC_DEFAULT to use Equation 7.21 of Hairer&Wanner
792 -  e4 - design parameter for embedded method, see coefficient E4 in ros4.f code from Hairer
793 
794    Level: developer
795 
796    Notes:
797    This routine encodes the design of fourth order Rosenbrock methods as described in Hairer and Wanner volume 2.
798    It is used here to implement several methods from the book and can be used to experiment with new methods.
799    It was written this way instead of by copying coefficients in order to provide better than double precision satisfaction of the order conditions.
800 
801 .seealso: [](chapter_ts), `TSRosW`, `TSRosWRegister()`
802 @*/
803 PetscErrorCode TSRosWRegisterRos4(TSRosWType name, PetscReal gamma, PetscReal a2, PetscReal a3, PetscReal b3, PetscReal e4)
804 {
805   /* Declare numeric constants so they can be quad precision without being truncated at double */
806   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;
807   PetscReal   a4, a32, a42, a43, b1, b2, b4, beta2p, beta3p, beta4p, beta32, beta42, beta43, beta32beta2p, beta4jbetajp;
808   PetscReal   A[4][4], Gamma[4][4], b[4], bm[4];
809   PetscScalar M[3][3], rhs[3];
810 
811   PetscFunctionBegin;
812   /* Step 1: choose Gamma (input) */
813   /* Step 2: choose a2,a3,a4; b1,b2,b3,b4 to satisfy order conditions */
814   if (a3 == PETSC_DEFAULT) a3 = (one / five - a2 / four) / (one / four - a2 / three); /* Eq 7.22 */
815   a4 = a3;                                                                            /* consequence of 7.20 */
816 
817   /* Solve order conditions 7.15a, 7.15c, 7.15e */
818   M[0][0] = one;
819   M[0][1] = one;
820   M[0][2] = one; /* 7.15a */
821   M[1][0] = 0.0;
822   M[1][1] = a2 * a2;
823   M[1][2] = a4 * a4; /* 7.15c */
824   M[2][0] = 0.0;
825   M[2][1] = a2 * a2 * a2;
826   M[2][2] = a4 * a4 * a4; /* 7.15e */
827   rhs[0]  = one - b3;
828   rhs[1]  = one / three - a3 * a3 * b3;
829   rhs[2]  = one / four - a3 * a3 * a3 * b3;
830   PetscCall(PetscKernel_A_gets_inverse_A_3(&M[0][0], 0, PETSC_FALSE, NULL));
831   b1 = PetscRealPart(M[0][0] * rhs[0] + M[0][1] * rhs[1] + M[0][2] * rhs[2]);
832   b2 = PetscRealPart(M[1][0] * rhs[0] + M[1][1] * rhs[1] + M[1][2] * rhs[2]);
833   b4 = PetscRealPart(M[2][0] * rhs[0] + M[2][1] * rhs[1] + M[2][2] * rhs[2]);
834 
835   /* Step 3 */
836   beta43       = (p56 - a2 * p43) / (b4 * a3 * a3 * (a3 - a2)); /* 7.21 */
837   beta32beta2p = p44 / (b4 * beta43);                           /* 7.15h */
838   beta4jbetajp = (p32 - b3 * beta32beta2p) / b4;
839   M[0][0]      = b2;
840   M[0][1]      = b3;
841   M[0][2]      = b4;
842   M[1][0]      = a4 * a4 * beta32beta2p - a3 * a3 * beta4jbetajp;
843   M[1][1]      = a2 * a2 * beta4jbetajp;
844   M[1][2]      = -a2 * a2 * beta32beta2p;
845   M[2][0]      = b4 * beta43 * a3 * a3 - p43;
846   M[2][1]      = -b4 * beta43 * a2 * a2;
847   M[2][2]      = 0;
848   rhs[0]       = one / two - gamma;
849   rhs[1]       = 0;
850   rhs[2]       = -a2 * a2 * p32;
851   PetscCall(PetscKernel_A_gets_inverse_A_3(&M[0][0], 0, PETSC_FALSE, NULL));
852   beta2p = PetscRealPart(M[0][0] * rhs[0] + M[0][1] * rhs[1] + M[0][2] * rhs[2]);
853   beta3p = PetscRealPart(M[1][0] * rhs[0] + M[1][1] * rhs[1] + M[1][2] * rhs[2]);
854   beta4p = PetscRealPart(M[2][0] * rhs[0] + M[2][1] * rhs[1] + M[2][2] * rhs[2]);
855 
856   /* Step 4: back-substitute */
857   beta32 = beta32beta2p / beta2p;
858   beta42 = (beta4jbetajp - beta43 * beta3p) / beta2p;
859 
860   /* Step 5: 7.15f and 7.20, then 7.16 */
861   a43 = 0;
862   a32 = p42 / (b3 * a3 * beta2p + b4 * a4 * beta2p);
863   a42 = a32;
864 
865   A[0][0]     = 0;
866   A[0][1]     = 0;
867   A[0][2]     = 0;
868   A[0][3]     = 0;
869   A[1][0]     = a2;
870   A[1][1]     = 0;
871   A[1][2]     = 0;
872   A[1][3]     = 0;
873   A[2][0]     = a3 - a32;
874   A[2][1]     = a32;
875   A[2][2]     = 0;
876   A[2][3]     = 0;
877   A[3][0]     = a4 - a43 - a42;
878   A[3][1]     = a42;
879   A[3][2]     = a43;
880   A[3][3]     = 0;
881   Gamma[0][0] = gamma;
882   Gamma[0][1] = 0;
883   Gamma[0][2] = 0;
884   Gamma[0][3] = 0;
885   Gamma[1][0] = beta2p - A[1][0];
886   Gamma[1][1] = gamma;
887   Gamma[1][2] = 0;
888   Gamma[1][3] = 0;
889   Gamma[2][0] = beta3p - beta32 - A[2][0];
890   Gamma[2][1] = beta32 - A[2][1];
891   Gamma[2][2] = gamma;
892   Gamma[2][3] = 0;
893   Gamma[3][0] = beta4p - beta42 - beta43 - A[3][0];
894   Gamma[3][1] = beta42 - A[3][1];
895   Gamma[3][2] = beta43 - A[3][2];
896   Gamma[3][3] = gamma;
897   b[0]        = b1;
898   b[1]        = b2;
899   b[2]        = b3;
900   b[3]        = b4;
901 
902   /* Construct embedded formula using given e4. We are solving Equation 7.18. */
903   bm[3] = b[3] - e4 * gamma;                                              /* using definition of E4 */
904   bm[2] = (p32 - beta4jbetajp * bm[3]) / (beta32 * beta2p);               /* fourth row of 7.18 */
905   bm[1] = (one / two - gamma - beta3p * bm[2] - beta4p * bm[3]) / beta2p; /* second row */
906   bm[0] = one - bm[1] - bm[2] - bm[3];                                    /* first row */
907 
908   {
909     const PetscReal misfit = a2 * a2 * bm[1] + a3 * a3 * bm[2] + a4 * a4 * bm[3] - one / three;
910     PetscCheck(PetscAbs(misfit) <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_SUP, "Assumptions violated, could not construct a third order embedded method");
911   }
912   PetscCall(TSRosWRegister(name, 4, 4, &A[0][0], &Gamma[0][0], b, bm, 0, NULL));
913   PetscFunctionReturn(0);
914 }
915 
916 /*
917  The step completion formula is
918 
919  x1 = x0 + b^T Y
920 
921  where Y is the multi-vector of stages corrections. This function can be called before or after ts->vec_sol has been
922  updated. Suppose we have a completion formula b and an embedded formula be of different order. We can write
923 
924  x1e = x0 + be^T Y
925      = x1 - b^T Y + be^T Y
926      = x1 + (be - b)^T Y
927 
928  so we can evaluate the method of different order even after the step has been optimistically completed.
929 */
930 static PetscErrorCode TSEvaluateStep_RosW(TS ts, PetscInt order, Vec U, PetscBool *done)
931 {
932   TS_RosW     *ros = (TS_RosW *)ts->data;
933   RosWTableau  tab = ros->tableau;
934   PetscScalar *w   = ros->work;
935   PetscInt     i;
936 
937   PetscFunctionBegin;
938   if (order == tab->order) {
939     if (ros->status == TS_STEP_INCOMPLETE) { /* Use standard completion formula */
940       PetscCall(VecCopy(ts->vec_sol, U));
941       for (i = 0; i < tab->s; i++) w[i] = tab->bt[i];
942       PetscCall(VecMAXPY(U, tab->s, w, ros->Y));
943     } else PetscCall(VecCopy(ts->vec_sol, U));
944     if (done) *done = PETSC_TRUE;
945     PetscFunctionReturn(0);
946   } else if (order == tab->order - 1) {
947     if (!tab->bembedt) goto unavailable;
948     if (ros->status == TS_STEP_INCOMPLETE) { /* Use embedded completion formula */
949       PetscCall(VecCopy(ts->vec_sol, U));
950       for (i = 0; i < tab->s; i++) w[i] = tab->bembedt[i];
951       PetscCall(VecMAXPY(U, tab->s, w, ros->Y));
952     } else { /* Use rollback-and-recomplete formula (bembedt - bt) */
953       for (i = 0; i < tab->s; i++) w[i] = tab->bembedt[i] - tab->bt[i];
954       PetscCall(VecCopy(ts->vec_sol, U));
955       PetscCall(VecMAXPY(U, tab->s, w, ros->Y));
956     }
957     if (done) *done = PETSC_TRUE;
958     PetscFunctionReturn(0);
959   }
960 unavailable:
961   if (done) *done = PETSC_FALSE;
962   else
963     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,
964             tab->order, order);
965   PetscFunctionReturn(0);
966 }
967 
968 static PetscErrorCode TSRollBack_RosW(TS ts)
969 {
970   TS_RosW *ros = (TS_RosW *)ts->data;
971 
972   PetscFunctionBegin;
973   PetscCall(VecCopy(ros->vec_sol_prev, ts->vec_sol));
974   PetscFunctionReturn(0);
975 }
976 
977 static PetscErrorCode TSStep_RosW(TS ts)
978 {
979   TS_RosW         *ros = (TS_RosW *)ts->data;
980   RosWTableau      tab = ros->tableau;
981   const PetscInt   s   = tab->s;
982   const PetscReal *At = tab->At, *Gamma = tab->Gamma, *ASum = tab->ASum, *GammaInv = tab->GammaInv;
983   const PetscReal *GammaExplicitCorr = tab->GammaExplicitCorr;
984   const PetscBool *GammaZeroDiag     = tab->GammaZeroDiag;
985   PetscScalar     *w                 = ros->work;
986   Vec             *Y = ros->Y, Ydot = ros->Ydot, Zdot = ros->Zdot, Zstage = ros->Zstage;
987   SNES             snes;
988   TSAdapt          adapt;
989   PetscInt         i, j, its, lits;
990   PetscInt         rejections = 0;
991   PetscBool        stageok, accept = PETSC_TRUE;
992   PetscReal        next_time_step = ts->time_step;
993   PetscInt         lag;
994 
995   PetscFunctionBegin;
996   if (!ts->steprollback) PetscCall(VecCopy(ts->vec_sol, ros->vec_sol_prev));
997 
998   ros->status = TS_STEP_INCOMPLETE;
999   while (!ts->reason && ros->status != TS_STEP_COMPLETE) {
1000     const PetscReal h = ts->time_step;
1001     for (i = 0; i < s; i++) {
1002       ros->stage_time = ts->ptime + h * ASum[i];
1003       PetscCall(TSPreStage(ts, ros->stage_time));
1004       if (GammaZeroDiag[i]) {
1005         ros->stage_explicit = PETSC_TRUE;
1006         ros->scoeff         = 1.;
1007       } else {
1008         ros->stage_explicit = PETSC_FALSE;
1009         ros->scoeff         = 1. / Gamma[i * s + i];
1010       }
1011 
1012       PetscCall(VecCopy(ts->vec_sol, Zstage));
1013       for (j = 0; j < i; j++) w[j] = At[i * s + j];
1014       PetscCall(VecMAXPY(Zstage, i, w, Y));
1015 
1016       for (j = 0; j < i; j++) w[j] = 1. / h * GammaInv[i * s + j];
1017       PetscCall(VecZeroEntries(Zdot));
1018       PetscCall(VecMAXPY(Zdot, i, w, Y));
1019 
1020       /* Initial guess taken from last stage */
1021       PetscCall(VecZeroEntries(Y[i]));
1022 
1023       if (!ros->stage_explicit) {
1024         PetscCall(TSGetSNES(ts, &snes));
1025         if (!ros->recompute_jacobian && !i) {
1026           PetscCall(SNESGetLagJacobian(snes, &lag));
1027           if (lag == 1) {                            /* use did not set a nontrivial lag, so lag over all stages */
1028             PetscCall(SNESSetLagJacobian(snes, -2)); /* Recompute the Jacobian on this solve, but not again for the rest of the stages */
1029           }
1030         }
1031         PetscCall(SNESSolve(snes, NULL, Y[i]));
1032         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 */ }
1033         PetscCall(SNESGetIterationNumber(snes, &its));
1034         PetscCall(SNESGetLinearSolveIterations(snes, &lits));
1035         ts->snes_its += its;
1036         ts->ksp_its += lits;
1037       } else {
1038         Mat J, Jp;
1039         PetscCall(VecZeroEntries(Ydot)); /* Evaluate Y[i]=G(t,Ydot=0,Zstage) */
1040         PetscCall(TSComputeIFunction(ts, ros->stage_time, Zstage, Ydot, Y[i], PETSC_FALSE));
1041         PetscCall(VecScale(Y[i], -1.0));
1042         PetscCall(VecAXPY(Y[i], -1.0, Zdot)); /*Y[i] = F(Zstage)-Zdot[=GammaInv*Y]*/
1043 
1044         PetscCall(VecZeroEntries(Zstage)); /* Zstage = GammaExplicitCorr[i,j] * Y[j] */
1045         for (j = 0; j < i; j++) w[j] = GammaExplicitCorr[i * s + j];
1046         PetscCall(VecMAXPY(Zstage, i, w, Y));
1047 
1048         /* Y[i] = Y[i] + Jac*Zstage[=Jac*GammaExplicitCorr[i,j] * Y[j]] */
1049         PetscCall(TSGetIJacobian(ts, &J, &Jp, NULL, NULL));
1050         PetscCall(TSComputeIJacobian(ts, ros->stage_time, ts->vec_sol, Ydot, 0, J, Jp, PETSC_FALSE));
1051         PetscCall(MatMult(J, Zstage, Zdot));
1052         PetscCall(VecAXPY(Y[i], -1.0, Zdot));
1053         ts->ksp_its += 1;
1054 
1055         PetscCall(VecScale(Y[i], h));
1056       }
1057       PetscCall(TSPostStage(ts, ros->stage_time, i, Y));
1058       PetscCall(TSGetAdapt(ts, &adapt));
1059       PetscCall(TSAdaptCheckStage(adapt, ts, ros->stage_time, Y[i], &stageok));
1060       if (!stageok) goto reject_step;
1061     }
1062 
1063     ros->status = TS_STEP_INCOMPLETE;
1064     PetscCall(TSEvaluateStep_RosW(ts, tab->order, ts->vec_sol, NULL));
1065     ros->status = TS_STEP_PENDING;
1066     PetscCall(TSGetAdapt(ts, &adapt));
1067     PetscCall(TSAdaptCandidatesClear(adapt));
1068     PetscCall(TSAdaptCandidateAdd(adapt, tab->name, tab->order, 1, tab->ccfl, (PetscReal)tab->s, PETSC_TRUE));
1069     PetscCall(TSAdaptChoose(adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
1070     ros->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
1071     if (!accept) { /* Roll back the current step */
1072       PetscCall(TSRollBack_RosW(ts));
1073       ts->time_step = next_time_step;
1074       goto reject_step;
1075     }
1076 
1077     ts->ptime += ts->time_step;
1078     ts->time_step = next_time_step;
1079     break;
1080 
1081   reject_step:
1082     ts->reject++;
1083     accept = PETSC_FALSE;
1084     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
1085       ts->reason = TS_DIVERGED_STEP_REJECTED;
1086       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
1087     }
1088   }
1089   PetscFunctionReturn(0);
1090 }
1091 
1092 static PetscErrorCode TSInterpolate_RosW(TS ts, PetscReal itime, Vec U)
1093 {
1094   TS_RosW         *ros = (TS_RosW *)ts->data;
1095   PetscInt         s = ros->tableau->s, pinterp = ros->tableau->pinterp, i, j;
1096   PetscReal        h;
1097   PetscReal        tt, t;
1098   PetscScalar     *bt;
1099   const PetscReal *Bt       = ros->tableau->binterpt;
1100   const PetscReal *GammaInv = ros->tableau->GammaInv;
1101   PetscScalar     *w        = ros->work;
1102   Vec             *Y        = ros->Y;
1103 
1104   PetscFunctionBegin;
1105   PetscCheck(Bt, PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "TSRosW %s does not have an interpolation formula", ros->tableau->name);
1106 
1107   switch (ros->status) {
1108   case TS_STEP_INCOMPLETE:
1109   case TS_STEP_PENDING:
1110     h = ts->time_step;
1111     t = (itime - ts->ptime) / h;
1112     break;
1113   case TS_STEP_COMPLETE:
1114     h = ts->ptime - ts->ptime_prev;
1115     t = (itime - ts->ptime) / h + 1; /* In the interval [0,1] */
1116     break;
1117   default:
1118     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Invalid TSStepStatus");
1119   }
1120   PetscCall(PetscMalloc1(s, &bt));
1121   for (i = 0; i < s; i++) bt[i] = 0;
1122   for (j = 0, tt = t; j < pinterp; j++, tt *= t) {
1123     for (i = 0; i < s; i++) bt[i] += Bt[i * pinterp + j] * tt;
1124   }
1125 
1126   /* y(t+tt*h) = y(t) + Sum bt(tt) * GammaInv * Ydot */
1127   /* U <- 0*/
1128   PetscCall(VecZeroEntries(U));
1129   /* U <- Sum bt_i * GammaInv(i,1:i) * Y(1:i) */
1130   for (j = 0; j < s; j++) w[j] = 0;
1131   for (j = 0; j < s; j++) {
1132     for (i = j; i < s; i++) w[j] += bt[i] * GammaInv[i * s + j];
1133   }
1134   PetscCall(VecMAXPY(U, i, w, Y));
1135   /* U <- y(t) + U */
1136   PetscCall(VecAXPY(U, 1, ros->vec_sol_prev));
1137 
1138   PetscCall(PetscFree(bt));
1139   PetscFunctionReturn(0);
1140 }
1141 
1142 /*------------------------------------------------------------*/
1143 
1144 static PetscErrorCode TSRosWTableauReset(TS ts)
1145 {
1146   TS_RosW    *ros = (TS_RosW *)ts->data;
1147   RosWTableau tab = ros->tableau;
1148 
1149   PetscFunctionBegin;
1150   if (!tab) PetscFunctionReturn(0);
1151   PetscCall(VecDestroyVecs(tab->s, &ros->Y));
1152   PetscCall(PetscFree(ros->work));
1153   PetscFunctionReturn(0);
1154 }
1155 
1156 static PetscErrorCode TSReset_RosW(TS ts)
1157 {
1158   TS_RosW *ros = (TS_RosW *)ts->data;
1159 
1160   PetscFunctionBegin;
1161   PetscCall(TSRosWTableauReset(ts));
1162   PetscCall(VecDestroy(&ros->Ydot));
1163   PetscCall(VecDestroy(&ros->Ystage));
1164   PetscCall(VecDestroy(&ros->Zdot));
1165   PetscCall(VecDestroy(&ros->Zstage));
1166   PetscCall(VecDestroy(&ros->vec_sol_prev));
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 static PetscErrorCode TSRosWGetVecs(TS ts, DM dm, Vec *Ydot, Vec *Zdot, Vec *Ystage, Vec *Zstage)
1171 {
1172   TS_RosW *rw = (TS_RosW *)ts->data;
1173 
1174   PetscFunctionBegin;
1175   if (Ydot) {
1176     if (dm && dm != ts->dm) {
1177       PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Ydot", Ydot));
1178     } else *Ydot = rw->Ydot;
1179   }
1180   if (Zdot) {
1181     if (dm && dm != ts->dm) {
1182       PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Zdot", Zdot));
1183     } else *Zdot = rw->Zdot;
1184   }
1185   if (Ystage) {
1186     if (dm && dm != ts->dm) {
1187       PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Ystage", Ystage));
1188     } else *Ystage = rw->Ystage;
1189   }
1190   if (Zstage) {
1191     if (dm && dm != ts->dm) {
1192       PetscCall(DMGetNamedGlobalVector(dm, "TSRosW_Zstage", Zstage));
1193     } else *Zstage = rw->Zstage;
1194   }
1195   PetscFunctionReturn(0);
1196 }
1197 
1198 static PetscErrorCode TSRosWRestoreVecs(TS ts, DM dm, Vec *Ydot, Vec *Zdot, Vec *Ystage, Vec *Zstage)
1199 {
1200   PetscFunctionBegin;
1201   if (Ydot) {
1202     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Ydot", Ydot));
1203   }
1204   if (Zdot) {
1205     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Zdot", Zdot));
1206   }
1207   if (Ystage) {
1208     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Ystage", Ystage));
1209   }
1210   if (Zstage) {
1211     if (dm && dm != ts->dm) PetscCall(DMRestoreNamedGlobalVector(dm, "TSRosW_Zstage", Zstage));
1212   }
1213   PetscFunctionReturn(0);
1214 }
1215 
1216 static PetscErrorCode DMCoarsenHook_TSRosW(DM fine, DM coarse, void *ctx)
1217 {
1218   PetscFunctionBegin;
1219   PetscFunctionReturn(0);
1220 }
1221 
1222 static PetscErrorCode DMRestrictHook_TSRosW(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
1223 {
1224   TS  ts = (TS)ctx;
1225   Vec Ydot, Zdot, Ystage, Zstage;
1226   Vec Ydotc, Zdotc, Ystagec, Zstagec;
1227 
1228   PetscFunctionBegin;
1229   PetscCall(TSRosWGetVecs(ts, fine, &Ydot, &Ystage, &Zdot, &Zstage));
1230   PetscCall(TSRosWGetVecs(ts, coarse, &Ydotc, &Ystagec, &Zdotc, &Zstagec));
1231   PetscCall(MatRestrict(restrct, Ydot, Ydotc));
1232   PetscCall(VecPointwiseMult(Ydotc, rscale, Ydotc));
1233   PetscCall(MatRestrict(restrct, Ystage, Ystagec));
1234   PetscCall(VecPointwiseMult(Ystagec, rscale, Ystagec));
1235   PetscCall(MatRestrict(restrct, Zdot, Zdotc));
1236   PetscCall(VecPointwiseMult(Zdotc, rscale, Zdotc));
1237   PetscCall(MatRestrict(restrct, Zstage, Zstagec));
1238   PetscCall(VecPointwiseMult(Zstagec, rscale, Zstagec));
1239   PetscCall(TSRosWRestoreVecs(ts, fine, &Ydot, &Ystage, &Zdot, &Zstage));
1240   PetscCall(TSRosWRestoreVecs(ts, coarse, &Ydotc, &Ystagec, &Zdotc, &Zstagec));
1241   PetscFunctionReturn(0);
1242 }
1243 
1244 static PetscErrorCode DMSubDomainHook_TSRosW(DM fine, DM coarse, void *ctx)
1245 {
1246   PetscFunctionBegin;
1247   PetscFunctionReturn(0);
1248 }
1249 
1250 static PetscErrorCode DMSubDomainRestrictHook_TSRosW(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
1251 {
1252   TS  ts = (TS)ctx;
1253   Vec Ydot, Zdot, Ystage, Zstage;
1254   Vec Ydots, Zdots, Ystages, Zstages;
1255 
1256   PetscFunctionBegin;
1257   PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage));
1258   PetscCall(TSRosWGetVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages));
1259 
1260   PetscCall(VecScatterBegin(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD));
1261   PetscCall(VecScatterEnd(gscat, Ydot, Ydots, INSERT_VALUES, SCATTER_FORWARD));
1262 
1263   PetscCall(VecScatterBegin(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD));
1264   PetscCall(VecScatterEnd(gscat, Ystage, Ystages, INSERT_VALUES, SCATTER_FORWARD));
1265 
1266   PetscCall(VecScatterBegin(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD));
1267   PetscCall(VecScatterEnd(gscat, Zdot, Zdots, INSERT_VALUES, SCATTER_FORWARD));
1268 
1269   PetscCall(VecScatterBegin(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD));
1270   PetscCall(VecScatterEnd(gscat, Zstage, Zstages, INSERT_VALUES, SCATTER_FORWARD));
1271 
1272   PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Ystage, &Zdot, &Zstage));
1273   PetscCall(TSRosWRestoreVecs(ts, subdm, &Ydots, &Ystages, &Zdots, &Zstages));
1274   PetscFunctionReturn(0);
1275 }
1276 
1277 /*
1278   This defines the nonlinear equation that is to be solved with SNES
1279   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
1280 */
1281 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes, Vec U, Vec F, TS ts)
1282 {
1283   TS_RosW  *ros = (TS_RosW *)ts->data;
1284   Vec       Ydot, Zdot, Ystage, Zstage;
1285   PetscReal shift = ros->scoeff / ts->time_step;
1286   DM        dm, dmsave;
1287 
1288   PetscFunctionBegin;
1289   PetscCall(SNESGetDM(snes, &dm));
1290   PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage));
1291   PetscCall(VecWAXPY(Ydot, shift, U, Zdot));   /* Ydot = shift*U + Zdot */
1292   PetscCall(VecWAXPY(Ystage, 1.0, U, Zstage)); /* Ystage = U + Zstage */
1293   dmsave = ts->dm;
1294   ts->dm = dm;
1295   PetscCall(TSComputeIFunction(ts, ros->stage_time, Ystage, Ydot, F, PETSC_FALSE));
1296   ts->dm = dmsave;
1297   PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage));
1298   PetscFunctionReturn(0);
1299 }
1300 
1301 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes, Vec U, Mat A, Mat B, TS ts)
1302 {
1303   TS_RosW  *ros = (TS_RosW *)ts->data;
1304   Vec       Ydot, Zdot, Ystage, Zstage;
1305   PetscReal shift = ros->scoeff / ts->time_step;
1306   DM        dm, dmsave;
1307 
1308   PetscFunctionBegin;
1309   /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */
1310   PetscCall(SNESGetDM(snes, &dm));
1311   PetscCall(TSRosWGetVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage));
1312   dmsave = ts->dm;
1313   ts->dm = dm;
1314   PetscCall(TSComputeIJacobian(ts, ros->stage_time, Ystage, Ydot, shift, A, B, PETSC_TRUE));
1315   ts->dm = dmsave;
1316   PetscCall(TSRosWRestoreVecs(ts, dm, &Ydot, &Zdot, &Ystage, &Zstage));
1317   PetscFunctionReturn(0);
1318 }
1319 
1320 static PetscErrorCode TSRosWTableauSetUp(TS ts)
1321 {
1322   TS_RosW    *ros = (TS_RosW *)ts->data;
1323   RosWTableau tab = ros->tableau;
1324 
1325   PetscFunctionBegin;
1326   PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &ros->Y));
1327   PetscCall(PetscMalloc1(tab->s, &ros->work));
1328   PetscFunctionReturn(0);
1329 }
1330 
1331 static PetscErrorCode TSSetUp_RosW(TS ts)
1332 {
1333   TS_RosW      *ros = (TS_RosW *)ts->data;
1334   DM            dm;
1335   SNES          snes;
1336   TSRHSJacobian rhsjacobian;
1337 
1338   PetscFunctionBegin;
1339   PetscCall(TSRosWTableauSetUp(ts));
1340   PetscCall(VecDuplicate(ts->vec_sol, &ros->Ydot));
1341   PetscCall(VecDuplicate(ts->vec_sol, &ros->Ystage));
1342   PetscCall(VecDuplicate(ts->vec_sol, &ros->Zdot));
1343   PetscCall(VecDuplicate(ts->vec_sol, &ros->Zstage));
1344   PetscCall(VecDuplicate(ts->vec_sol, &ros->vec_sol_prev));
1345   PetscCall(TSGetDM(ts, &dm));
1346   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSRosW, DMRestrictHook_TSRosW, ts));
1347   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSRosW, DMSubDomainRestrictHook_TSRosW, ts));
1348   /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */
1349   PetscCall(TSGetSNES(ts, &snes));
1350   if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESKSPONLY));
1351   PetscCall(DMTSGetRHSJacobian(dm, &rhsjacobian, NULL));
1352   if (rhsjacobian == TSComputeRHSJacobianConstant) {
1353     Mat Amat, Pmat;
1354 
1355     /* Set the SNES matrix to be different from the RHS matrix because there is no way to reconstruct shift*M-J */
1356     PetscCall(SNESGetJacobian(snes, &Amat, &Pmat, NULL, NULL));
1357     if (Amat && Amat == ts->Arhs) {
1358       if (Amat == Pmat) {
1359         PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat));
1360         PetscCall(SNESSetJacobian(snes, Amat, Amat, NULL, NULL));
1361       } else {
1362         PetscCall(MatDuplicate(ts->Arhs, MAT_COPY_VALUES, &Amat));
1363         PetscCall(SNESSetJacobian(snes, Amat, NULL, NULL, NULL));
1364         if (Pmat && Pmat == ts->Brhs) {
1365           PetscCall(MatDuplicate(ts->Brhs, MAT_COPY_VALUES, &Pmat));
1366           PetscCall(SNESSetJacobian(snes, NULL, Pmat, NULL, NULL));
1367           PetscCall(MatDestroy(&Pmat));
1368         }
1369       }
1370       PetscCall(MatDestroy(&Amat));
1371     }
1372   }
1373   PetscFunctionReturn(0);
1374 }
1375 /*------------------------------------------------------------*/
1376 
1377 static PetscErrorCode TSSetFromOptions_RosW(TS ts, PetscOptionItems *PetscOptionsObject)
1378 {
1379   TS_RosW *ros = (TS_RosW *)ts->data;
1380   SNES     snes;
1381 
1382   PetscFunctionBegin;
1383   PetscOptionsHeadBegin(PetscOptionsObject, "RosW ODE solver options");
1384   {
1385     RosWTableauLink link;
1386     PetscInt        count, choice;
1387     PetscBool       flg;
1388     const char    **namelist;
1389 
1390     for (link = RosWTableauList, count = 0; link; link = link->next, count++)
1391       ;
1392     PetscCall(PetscMalloc1(count, (char ***)&namelist));
1393     for (link = RosWTableauList, count = 0; link; link = link->next, count++) namelist[count] = link->tab.name;
1394     PetscCall(PetscOptionsEList("-ts_rosw_type", "Family of Rosenbrock-W method", "TSRosWSetType", (const char *const *)namelist, count, ros->tableau->name, &choice, &flg));
1395     if (flg) PetscCall(TSRosWSetType(ts, namelist[choice]));
1396     PetscCall(PetscFree(namelist));
1397 
1398     PetscCall(PetscOptionsBool("-ts_rosw_recompute_jacobian", "Recompute the Jacobian at each stage", "TSRosWSetRecomputeJacobian", ros->recompute_jacobian, &ros->recompute_jacobian, NULL));
1399   }
1400   PetscOptionsHeadEnd();
1401   /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */
1402   PetscCall(TSGetSNES(ts, &snes));
1403   if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESKSPONLY));
1404   PetscFunctionReturn(0);
1405 }
1406 
1407 static PetscErrorCode TSView_RosW(TS ts, PetscViewer viewer)
1408 {
1409   TS_RosW  *ros = (TS_RosW *)ts->data;
1410   PetscBool iascii;
1411 
1412   PetscFunctionBegin;
1413   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1414   if (iascii) {
1415     RosWTableau tab = ros->tableau;
1416     TSRosWType  rostype;
1417     char        buf[512];
1418     PetscInt    i;
1419     PetscReal   abscissa[512];
1420     PetscCall(TSRosWGetType(ts, &rostype));
1421     PetscCall(PetscViewerASCIIPrintf(viewer, "  Rosenbrock-W %s\n", rostype));
1422     PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, tab->ASum));
1423     PetscCall(PetscViewerASCIIPrintf(viewer, "  Abscissa of A       = %s\n", buf));
1424     for (i = 0; i < tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i];
1425     PetscCall(PetscFormatRealArray(buf, sizeof(buf), "% 8.6f", tab->s, abscissa));
1426     PetscCall(PetscViewerASCIIPrintf(viewer, "  Abscissa of A+Gamma = %s\n", buf));
1427   }
1428   PetscFunctionReturn(0);
1429 }
1430 
1431 static PetscErrorCode TSLoad_RosW(TS ts, PetscViewer viewer)
1432 {
1433   SNES    snes;
1434   TSAdapt adapt;
1435 
1436   PetscFunctionBegin;
1437   PetscCall(TSGetAdapt(ts, &adapt));
1438   PetscCall(TSAdaptLoad(adapt, viewer));
1439   PetscCall(TSGetSNES(ts, &snes));
1440   PetscCall(SNESLoad(snes, viewer));
1441   /* function and Jacobian context for SNES when used with TS is always ts object */
1442   PetscCall(SNESSetFunction(snes, NULL, NULL, ts));
1443   PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, ts));
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 /*@C
1448   TSRosWSetType - Set the type of Rosenbrock-W, `TSROSW`, scheme
1449 
1450   Logically collective
1451 
1452   Input Parameters:
1453 +  ts - timestepping context
1454 -  roswtype - type of Rosenbrock-W scheme
1455 
1456   Level: beginner
1457 
1458 .seealso: [](chapter_ts), `TSRosWGetType()`, `TSROSW`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`, `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWARK3`
1459 @*/
1460 PetscErrorCode TSRosWSetType(TS ts, TSRosWType roswtype)
1461 {
1462   PetscFunctionBegin;
1463   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1464   PetscValidCharPointer(roswtype, 2);
1465   PetscTryMethod(ts, "TSRosWSetType_C", (TS, TSRosWType), (ts, roswtype));
1466   PetscFunctionReturn(0);
1467 }
1468 
1469 /*@C
1470   TSRosWGetType - Get the type of Rosenbrock-W scheme
1471 
1472   Logically collective
1473 
1474   Input Parameter:
1475 .  ts - timestepping context
1476 
1477   Output Parameter:
1478 .  rostype - type of Rosenbrock-W scheme
1479 
1480   Level: intermediate
1481 
1482 .seealso: [](chapter_ts), `TSRosWType`, `TSRosWSetType()`
1483 @*/
1484 PetscErrorCode TSRosWGetType(TS ts, TSRosWType *rostype)
1485 {
1486   PetscFunctionBegin;
1487   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1488   PetscUseMethod(ts, "TSRosWGetType_C", (TS, TSRosWType *), (ts, rostype));
1489   PetscFunctionReturn(0);
1490 }
1491 
1492 /*@C
1493   TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step.
1494 
1495   Logically collective
1496 
1497   Input Parameters:
1498 +  ts - timestepping context
1499 -  flg - `PETSC_TRUE` to recompute the Jacobian at each stage
1500 
1501   Level: intermediate
1502 
1503 .seealso: [](chapter_ts), `TSRosWType`, `TSRosWGetType()`
1504 @*/
1505 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts, PetscBool flg)
1506 {
1507   PetscFunctionBegin;
1508   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1509   PetscTryMethod(ts, "TSRosWSetRecomputeJacobian_C", (TS, PetscBool), (ts, flg));
1510   PetscFunctionReturn(0);
1511 }
1512 
1513 static PetscErrorCode TSRosWGetType_RosW(TS ts, TSRosWType *rostype)
1514 {
1515   TS_RosW *ros = (TS_RosW *)ts->data;
1516 
1517   PetscFunctionBegin;
1518   *rostype = ros->tableau->name;
1519   PetscFunctionReturn(0);
1520 }
1521 
1522 static PetscErrorCode TSRosWSetType_RosW(TS ts, TSRosWType rostype)
1523 {
1524   TS_RosW        *ros = (TS_RosW *)ts->data;
1525   PetscBool       match;
1526   RosWTableauLink link;
1527 
1528   PetscFunctionBegin;
1529   if (ros->tableau) {
1530     PetscCall(PetscStrcmp(ros->tableau->name, rostype, &match));
1531     if (match) PetscFunctionReturn(0);
1532   }
1533   for (link = RosWTableauList; link; link = link->next) {
1534     PetscCall(PetscStrcmp(link->tab.name, rostype, &match));
1535     if (match) {
1536       if (ts->setupcalled) PetscCall(TSRosWTableauReset(ts));
1537       ros->tableau = &link->tab;
1538       if (ts->setupcalled) PetscCall(TSRosWTableauSetUp(ts));
1539       ts->default_adapt_type = ros->tableau->bembed ? TSADAPTBASIC : TSADAPTNONE;
1540       PetscFunctionReturn(0);
1541     }
1542   }
1543   SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", rostype);
1544 }
1545 
1546 static PetscErrorCode TSRosWSetRecomputeJacobian_RosW(TS ts, PetscBool flg)
1547 {
1548   TS_RosW *ros = (TS_RosW *)ts->data;
1549 
1550   PetscFunctionBegin;
1551   ros->recompute_jacobian = flg;
1552   PetscFunctionReturn(0);
1553 }
1554 
1555 static PetscErrorCode TSDestroy_RosW(TS ts)
1556 {
1557   PetscFunctionBegin;
1558   PetscCall(TSReset_RosW(ts));
1559   if (ts->dm) {
1560     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSRosW, DMRestrictHook_TSRosW, ts));
1561     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSRosW, DMSubDomainRestrictHook_TSRosW, ts));
1562   }
1563   PetscCall(PetscFree(ts->data));
1564   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", NULL));
1565   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", NULL));
1566   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", NULL));
1567   PetscFunctionReturn(0);
1568 }
1569 
1570 /* ------------------------------------------------------------ */
1571 /*MC
1572       TSROSW - ODE solver using Rosenbrock-W schemes
1573 
1574   These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly
1575   nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part
1576   of the equation using `TSSetIFunction()` and the non-stiff part with `TSSetRHSFunction()`.
1577 
1578   Level: beginner
1579 
1580   Notes:
1581   This method currently only works with autonomous ODE and DAE.
1582 
1583   Consider trying `TSARKIMEX` if the stiff part is strongly nonlinear.
1584 
1585   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
1586 
1587   Developer Notes:
1588   Rosenbrock-W methods are typically specified for autonomous ODE
1589 
1590 $  udot = f(u)
1591 
1592   by the stage equations
1593 
1594 $  k_i = h f(u_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j
1595 
1596   and step completion formula
1597 
1598 $  u_1 = u_0 + sum_j b_j k_j
1599 
1600   with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(u)
1601   and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner,
1602   we define new variables for the stage equations
1603 
1604 $  y_i = gamma_ij k_j
1605 
1606   The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define
1607 
1608 $  A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-1}
1609 
1610   to rewrite the method as
1611 
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 
1615    where we have introduced the mass matrix M. Continue by defining
1616 
1617 $  ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j
1618 
1619    or, more compactly in tensor notation
1620 
1621 $  Ydot = 1/h (Gamma^{-1} \otimes I) Y .
1622 
1623    Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current
1624    stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the
1625    equation
1626 
1627 $  g(u_0 + sum_j a_ij y_j + y_i, ydot_i) = 0
1628 
1629    with initial guess y_i = 0.
1630 
1631 .seealso: [](chapter_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSRosWSetType()`, `TSRosWRegister()`, `TSROSWTHETA1`, `TSROSWTHETA2`, `TSROSW2M`, `TSROSW2P`, `TSROSWRA3PW`, `TSROSWRA34PW2`, `TSROSWRODAS3`,
1632           `TSROSWSANDU3`, `TSROSWASSP3P3S1C`, `TSROSWLASSP3P4S2C`, `TSROSWLLSSP3P4S2C`, `TSROSWGRK4T`, `TSROSWSHAMP4`, `TSROSWVELDD4`, `TSROSW4L`, `TSType`
1633 M*/
1634 PETSC_EXTERN PetscErrorCode TSCreate_RosW(TS ts)
1635 {
1636   TS_RosW *ros;
1637 
1638   PetscFunctionBegin;
1639   PetscCall(TSRosWInitializePackage());
1640 
1641   ts->ops->reset          = TSReset_RosW;
1642   ts->ops->destroy        = TSDestroy_RosW;
1643   ts->ops->view           = TSView_RosW;
1644   ts->ops->load           = TSLoad_RosW;
1645   ts->ops->setup          = TSSetUp_RosW;
1646   ts->ops->step           = TSStep_RosW;
1647   ts->ops->interpolate    = TSInterpolate_RosW;
1648   ts->ops->evaluatestep   = TSEvaluateStep_RosW;
1649   ts->ops->rollback       = TSRollBack_RosW;
1650   ts->ops->setfromoptions = TSSetFromOptions_RosW;
1651   ts->ops->snesfunction   = SNESTSFormFunction_RosW;
1652   ts->ops->snesjacobian   = SNESTSFormJacobian_RosW;
1653 
1654   ts->usessnes = PETSC_TRUE;
1655 
1656   PetscCall(PetscNew(&ros));
1657   ts->data = (void *)ros;
1658 
1659   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWGetType_C", TSRosWGetType_RosW));
1660   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetType_C", TSRosWSetType_RosW));
1661   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSRosWSetRecomputeJacobian_C", TSRosWSetRecomputeJacobian_RosW));
1662 
1663   PetscCall(TSRosWSetType(ts, TSRosWDefault));
1664   PetscFunctionReturn(0);
1665 }
1666