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