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