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