xref: /petsc/src/ts/impls/multirate/mprk.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1 /*
2   Code for time stepping with the Multirate Partitioned Runge-Kutta method
3 
4   Notes:
5   1) The general system is written as
6      Udot = F(t,U)
7      if one does not split the RHS function, but gives the indexes for both slow and fast components;
8   2) The general system is written as
9      Usdot = Fs(t,Us,Uf)
10      Ufdot = Ff(t,Us,Uf)
11      for component-wise partitioned system,
12      users should split the RHS function themselves and also provide the indexes for both slow and fast components.
13   3) To correct The confusing terminology in the paper, we use 'slow method', 'slow buffer method' and 'fast method' to denote the methods applied to 'slow region', 'slow buffer region' and 'fast region' respectively. The 'slow method' in the original paper actually means the 'slow buffer method'.
14   4) Why does the buffer region have to be inside the slow region? The buffer region is treated with a slow method essentially. Applying the slow method to a region with a fast characteristic time scale is apparently not a good choice.
15 
16   Reference:
17   Emil M. Constantinescu, Adrian Sandu, Multirate Timestepping Methods for Hyperbolic Conservation Laws, Journal of Scientific Computing 2007
18 */
19 
20 #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
21 #include <petscdm.h>
22 
23 static TSMPRKType TSMPRKDefault = TSMPRK2A22;
24 static PetscBool  TSMPRKRegisterAllCalled;
25 static PetscBool  TSMPRKPackageInitialized;
26 
27 typedef struct _MPRKTableau *MPRKTableau;
28 struct _MPRKTableau {
29   char      *name;
30   PetscInt   order;           /* Classical approximation order of the method i */
31   PetscInt   sbase;           /* Number of stages in the base method*/
32   PetscInt   s;               /* Number of stages */
33   PetscInt   np;              /* Number of partitions */
34   PetscReal *Af, *bf, *cf;    /* Tableau for fast components */
35   PetscReal *Amb, *bmb, *cmb; /* Tableau for medium components */
36   PetscInt  *rmb;             /* Array of flags for repeated stages in medium method */
37   PetscReal *Asb, *bsb, *csb; /* Tableau for slow components */
38   PetscInt  *rsb;             /* Array of flags for repeated staged in slow method*/
39 };
40 typedef struct _MPRKTableauLink *MPRKTableauLink;
41 struct _MPRKTableauLink {
42   struct _MPRKTableau tab;
43   MPRKTableauLink     next;
44 };
45 static MPRKTableauLink MPRKTableauList;
46 
47 typedef struct {
48   MPRKTableau  tableau;
49   Vec         *Y; /* States computed during the step                           */
50   Vec         *YdotRHS;
51   Vec         *YdotRHS_slow;         /* Function evaluations by slow tableau for slow components  */
52   Vec         *YdotRHS_slowbuffer;   /* Function evaluations by medium tableau for slow components  */
53   Vec         *YdotRHS_medium;       /* Function evaluations by medium tableau for medium components*/
54   Vec         *YdotRHS_mediumbuffer; /* Function evaluations by fast tableau for medium components  */
55   Vec         *YdotRHS_fast;         /* Function evaluations by fast tableau for fast components  */
56   PetscScalar *work_slow;            /* Scalar work_slow by slow tableau                          */
57   PetscScalar *work_slowbuffer;      /* Scalar work_slow by slow tableau                          */
58   PetscScalar *work_medium;          /* Scalar work_slow by medium tableau                        */
59   PetscScalar *work_mediumbuffer;    /* Scalar work_mediumbuffer by fast tableau                          */
60   PetscScalar *work_fast;            /* Scalar work_fast by fast tableau                          */
61   PetscReal    stage_time;
62   TSStepStatus status;
63   PetscReal    ptime;
64   PetscReal    time_step;
65   IS           is_slow, is_slowbuffer, is_medium, is_mediumbuffer, is_fast;
66   TS           subts_slow, subts_slowbuffer, subts_medium, subts_mediumbuffer, subts_fast;
67 } TS_MPRK;
68 
69 static PetscErrorCode TSMPRKGenerateTableau2(PetscInt ratio, PetscInt s, const PetscReal Abase[], const PetscReal bbase[], PetscReal A1[], PetscReal b1[], PetscReal A2[], PetscReal b2[])
70 {
71   PetscInt i, j, k, l;
72 
73   PetscFunctionBegin;
74   for (k = 0; k < ratio; k++) {
75     /* diagonal blocks */
76     for (i = 0; i < s; i++)
77       for (j = 0; j < s; j++) {
78         A1[(k * s + i) * ratio * s + k * s + j] = Abase[i * s + j];
79         A2[(k * s + i) * ratio * s + k * s + j] = Abase[i * s + j] / ratio;
80       }
81     /* off diagonal blocks */
82     for (l = 0; l < k; l++)
83       for (i = 0; i < s; i++)
84         for (j = 0; j < s; j++) A2[(k * s + i) * ratio * s + l * s + j] = bbase[j] / ratio;
85     for (j = 0; j < s; j++) {
86       b1[k * s + j] = bbase[j] / ratio;
87       b2[k * s + j] = bbase[j] / ratio;
88     }
89   }
90   PetscFunctionReturn(PETSC_SUCCESS);
91 }
92 
93 static PetscErrorCode TSMPRKGenerateTableau3(PetscInt ratio, PetscInt s, const PetscReal Abase[], const PetscReal bbase[], PetscReal A1[], PetscReal b1[], PetscReal A2[], PetscReal b2[], PetscReal A3[], PetscReal b3[])
94 {
95   PetscInt i, j, k, l, m, n;
96 
97   PetscFunctionBegin;
98   for (k = 0; k < ratio; k++) { /* diagonal blocks of size ratio*s by ratio*s */
99     for (l = 0; l < ratio; l++) /* diagonal sub-blocks of size s by s */
100       for (i = 0; i < s; i++)
101         for (j = 0; j < s; j++) {
102           A1[((k * ratio + l) * s + i) * ratio * ratio * s + (k * ratio + l) * s + j] = Abase[i * s + j];
103           A2[((k * ratio + l) * s + i) * ratio * ratio * s + (k * ratio + l) * s + j] = Abase[i * s + j] / ratio;
104           A3[((k * ratio + l) * s + i) * ratio * ratio * s + (k * ratio + l) * s + j] = Abase[i * s + j] / ratio / ratio;
105         }
106     for (l = 0; l < k; l++) /* off-diagonal blocks of size ratio*s by ratio*s */
107       for (m = 0; m < ratio; m++)
108         for (n = 0; n < ratio; n++)
109           for (i = 0; i < s; i++)
110             for (j = 0; j < s; j++) {
111               A2[((k * ratio + m) * s + i) * ratio * ratio * s + (l * ratio + n) * s + j] = bbase[j] / ratio / ratio;
112               A3[((k * ratio + m) * s + i) * ratio * ratio * s + (l * ratio + n) * s + j] = bbase[j] / ratio / ratio;
113             }
114     for (m = 0; m < ratio; m++)
115       for (n = 0; n < m; n++) /* off-diagonal sub-blocks of size s by s in the diagonal blocks */
116         for (i = 0; i < s; i++)
117           for (j = 0; j < s; j++) A3[((k * ratio + m) * s + i) * ratio * ratio * s + (k * ratio + n) * s + j] = bbase[j] / ratio / ratio;
118     for (n = 0; n < ratio; n++)
119       for (j = 0; j < s; j++) {
120         b1[(k * ratio + n) * s + j] = bbase[j] / ratio / ratio;
121         b2[(k * ratio + n) * s + j] = bbase[j] / ratio / ratio;
122         b3[(k * ratio + n) * s + j] = bbase[j] / ratio / ratio;
123       }
124   }
125   PetscFunctionReturn(PETSC_SUCCESS);
126 }
127 
128 /*MC
129      TSMPRK2A22 - Second Order Multirate Partitioned Runge Kutta scheme based on RK2A.
130 
131      This method has four stages for slow and fast parts. The refinement factor of the stepsize is 2.
132      r = 2, np = 2
133 
134      Options Database Key:
135 .     -ts_mprk_type 2a22 - select this scheme
136 
137      Level: advanced
138 
139 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
140 M*/
141 /*MC
142      TSMPRK2A23 - Second Order Multirate Partitioned Runge-Kutta scheme based on RK2A.
143 
144      This method has eight stages for slow and medium and fast parts. The refinement factor of the stepsize is 2.
145      r = 2, np = 3
146 
147      Options Database Key:
148 .     -ts_mprk_type 2a23 - select this scheme
149 
150      Level: advanced
151 
152 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
153 M*/
154 /*MC
155      TSMPRK2A32 - Second Order Multirate Partitioned Runge-Kutta scheme based on RK2A.
156 
157      This method has four stages for slow and fast parts. The refinement factor of the stepsize is 3.
158      r = 3, np = 2
159 
160      Options Database Key:
161 .     -ts_mprk_type 2a32 - select this scheme
162 
163      Level: advanced
164 
165 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
166 M*/
167 /*MC
168      TSMPRK2A33 - Second Order Multirate Partitioned Runge-Kutta scheme based on RK2A.
169 
170      This method has eight stages for slow and medium and fast parts. The refinement factor of the stepsize is 3.
171      r = 3, np = 3
172 
173      Options Database Key:
174 .     -ts_mprk_type 2a33- select this scheme
175 
176      Level: advanced
177 
178 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
179 M*/
180 /*MC
181      TSMPRK3P2M - Third Order Multirate Partitioned Runge-Kutta scheme.
182 
183      This method has eight stages for both slow and fast parts.
184 
185      Options Database Key:
186 .     -ts_mprk_type pm3 - select this scheme
187 
188      Level: advanced
189 
190 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
191 M*/
192 /*MC
193      TSMPRKP2 - Second Order Multirate Partitioned Runge-Kutta scheme.
194 
195      This method has five stages for both slow and fast parts.
196 
197      Options Database Key:
198 .     -ts_mprk_type p2 - select this scheme
199 
200      Level: advanced
201 
202 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
203 M*/
204 /*MC
205      TSMPRKP3 - Third Order Multirate Partitioned Runge-Kutta scheme.
206 
207      This method has ten stages for both slow and fast parts.
208 
209      Options Database Key:
210 .     -ts_mprk_type p3 - select this scheme
211 
212      Level: advanced
213 
214 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKType`, `TSMPRKSetType()`
215 M*/
216 
217 /*@C
218   TSMPRKRegisterAll - Registers all of the Partitioned Runge-Kutta explicit methods in `TSMPRK`
219 
220   Not Collective, but should be called by all processes which will need the schemes to be registered
221 
222   Level: advanced
223 
224 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKRegisterDestroy()`
225 @*/
226 PetscErrorCode TSMPRKRegisterAll(void)
227 {
228   PetscFunctionBegin;
229   if (TSMPRKRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
230   TSMPRKRegisterAllCalled = PETSC_TRUE;
231 
232 #define RC PetscRealConstant
233   {
234     const PetscReal Abase[2][2] =
235       {
236         {0,       0},
237         {RC(1.0), 0}
238     },
239                     bbase[2] = {RC(0.5), RC(0.5)};
240     PetscReal Asb[4][4] = {{0}}, Af[4][4] = {{0}}, bsb[4] = {0}, bf[4] = {0};
241     PetscInt  rsb[4] = {0, 0, 1, 2};
242     PetscCall(TSMPRKGenerateTableau2(2, 2, &Abase[0][0], bbase, &Asb[0][0], bsb, &Af[0][0], bf));
243     PetscCall(TSMPRKRegister(TSMPRK2A22, 2, 2, 2, 1, &Asb[0][0], bsb, NULL, rsb, NULL, NULL, NULL, NULL, &Af[0][0], bf, NULL));
244   }
245   {
246     const PetscReal Abase[2][2] =
247       {
248         {0,       0},
249         {RC(1.0), 0}
250     },
251                     bbase[2] = {RC(0.5), RC(0.5)};
252     PetscReal Asb[8][8] = {{0}}, Amb[8][8] = {{0}}, Af[8][8] = {{0}}, bsb[8] = {0}, bmb[8] = {0}, bf[8] = {0};
253     PetscInt  rsb[8] = {0, 0, 1, 2, 1, 2, 1, 2}, rmb[8] = {0, 0, 1, 2, 0, 0, 5, 6};
254     PetscCall(TSMPRKGenerateTableau3(2, 2, &Abase[0][0], bbase, &Asb[0][0], bsb, &Amb[0][0], bmb, &Af[0][0], bf));
255     PetscCall(TSMPRKRegister(TSMPRK2A23, 2, 2, 2, 2, &Asb[0][0], bsb, NULL, rsb, &Amb[0][0], bmb, NULL, rmb, &Af[0][0], bf, NULL));
256   }
257   {
258     const PetscReal Abase[2][2] =
259       {
260         {0,       0},
261         {RC(1.0), 0}
262     },
263                     bbase[2] = {RC(0.5), RC(0.5)};
264     PetscReal Asb[6][6] = {{0}}, Af[6][6] = {{0}}, bsb[6] = {0}, bf[6] = {0};
265     PetscInt  rsb[6] = {0, 0, 1, 2, 1, 2};
266     PetscCall(TSMPRKGenerateTableau2(3, 2, &Abase[0][0], bbase, &Asb[0][0], bsb, &Af[0][0], bf));
267     PetscCall(TSMPRKRegister(TSMPRK2A32, 2, 2, 3, 1, &Asb[0][0], bsb, NULL, rsb, NULL, NULL, NULL, NULL, &Af[0][0], bf, NULL));
268   }
269   {
270     const PetscReal Abase[2][2] =
271       {
272         {0,       0},
273         {RC(1.0), 0}
274     },
275                     bbase[2] = {RC(0.5), RC(0.5)};
276     PetscReal Asb[18][18] = {{0}}, Amb[18][18] = {{0}}, Af[18][18] = {{0}}, bsb[18] = {0}, bmb[18] = {0}, bf[18] = {0};
277     PetscInt  rsb[18] = {0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}, rmb[18] = {0, 0, 1, 2, 1, 2, 0, 0, 7, 8, 7, 8, 0, 0, 13, 14, 13, 14};
278     PetscCall(TSMPRKGenerateTableau3(3, 2, &Abase[0][0], bbase, &Asb[0][0], bsb, &Amb[0][0], bmb, &Af[0][0], bf));
279     PetscCall(TSMPRKRegister(TSMPRK2A33, 2, 2, 3, 3, &Asb[0][0], bsb, NULL, rsb, &Amb[0][0], bmb, NULL, rmb, &Af[0][0], bf, NULL));
280   }
281   /*
282     PetscReal
283       Asb[8][8] = {{Abase[0][0],Abase[0][1],0,0,0,0,0,0},
284                    {Abase[1][0],Abase[1][1],0,0,0,0,0,0},
285                    {0,0,Abase[0][0],Abase[0][1],0,0,0,0},
286                    {0,0,Abase[1][0],Abase[1][1],0,0,0,0},
287                    {0,0,0,0,Abase[0][0],Abase[0][1],0,0},
288                    {0,0,0,0,Abase[1][0],Abase[1][1],0,0},
289                    {0,0,0,0,0,0,Abase[0][0],Abase[0][1]},
290                    {0,0,0,0,0,0,Abase[1][0],Abase[1][1]}},
291       Amb[8][8] = {{Abase[0][0]/m,Abase[0][1]/m,0,0,0,0,0,0},
292                    {Abase[1][0]/m,Abase[1][1]/m,0,0,0,0,0,0},
293                    {0,0,Abase[0][0]/m,Abase[0][1]/m,0,0,0,0},
294                    {0,0,Abase[1][0]/m,Abase[1][1]/m,0,0,0,0},
295                    {bbase[0]/m,bbase[1]/m,bbase[0]/m,bbase[1]/m,Abase[0][0]/m,Abase[0][1]/m,0,0},
296                    {bbase[0]/m,bbase[1]/m,bbase[0]/m,bbase[1]/m,Abase[1][0]/m,Abase[1][1]/m,0,0},
297                    {bbase[0]/m,bbase[1]/m,bbase[0]/m,bbase[1]/m,0,0,Abase[0][0]/m,Abase[0][1]/m},
298                    {bbase[0]/m,bbase[1]/m,bbase[0]/m,bbase[1]/m,0,0,Abase[1][0]/m,Abase[1][1]/m}},
299       Af[8][8] = {{Abase[0][0]/m/m,Abase[0][1]/m/m,0,0,0,0,0,0},
300                    {Abase[1][0]/m/m,Abase[1][1]/m/m,0,0,0,0,0,0},
301                    {0,0,Abase[0][0]/m/m,Abase[0][1]/m/m,0,0,0,0},
302                    {0,0,Abase[1][0]/m/m,Abase[1][1]/m/m,0,0,0,0},
303                    {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,Abase[0][0]/m/m,Abase[0][1]/m/m,0,0},
304                    {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,Abase[1][0]/m/m,Abase[1][1]/m/m,0,0},
305                    {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,Abase[0][0]/m,Abase[0][1]/m},
306                    {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,Abase[1][0]/m,Abase[1][1]/m}},
307       bsb[8]    = {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m},
308       bmb[8]    = {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m,bbase[1]/m/m},
309       bf[8]     = {bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m/m,bbase[0]/m/m,bbase[1]/m,bbase[0]/m/m,bbase[1]/m/m},
310 */
311   /*{
312       const PetscReal
313         As[8][8] = {{0,0,0,0,0,0,0,0},
314                     {RC(1.0)/RC(2.0),0,0,0,0,0,0,0},
315                     {RC(-1.0)/RC(6.0),RC(2.0)/RC(3.0),0,0,0,0,0,0},
316                     {RC(1.0)/RC(3.0),RC(-1.0)/RC(3.0),RC(1.0),0,0,0,0,0},
317                     {0,0,0,0,0,0,0,0},
318                     {0,0,0,0,RC(1.0)/RC(2.0),0,0,0},
319                     {0,0,0,0,RC(-1.0)/RC(6.0),RC(2.0)/RC(3.0),0,0},
320                     {0,0,0,0,RC(1.0)/RC(3.0),RC(-1.0)/RC(3.0),RC(1.0),0}},
321          A[8][8] = {{0,0,0,0,0,0,0,0},
322                     {RC(1.0)/RC(4.0),0,0,0,0,0,0,0},
323                     {RC(-1.0)/RC(12.0),RC(1.0)/RC(3.0),0,0,0,0,0,0},
324                     {RC(1.0)/RC(6.0),RC(-1.0)/RC(6.0),RC(1.0)/RC(2.0),0,0,0,0,0},
325                     {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),0,0,0,0},
326                     {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),RC(1.0)/RC(4.0),0,0,0},
327                     {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),RC(-1.0)/RC(12.0),RC(1.0)/RC(3.0),0,0},
328                     {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(-1.0)/RC(6.0),RC(1.0)/RC(2.0),0}},
329           bs[8] = {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0)},
330            b[8] = {RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0),RC(1.0)/RC(12.0),RC(1.0)/RC(6.0),RC(1.0)/RC(6.0),RC(1.0)/RC(12.0)};
331            PetscCall(TSMPRKRegister(TSMPRKPM3,3,8,&As[0][0],bs,NULL,&A[0][0],b,NULL));
332   }*/
333 
334   {
335     const PetscReal Asb[5][5] =
336       {
337         {0,                 0, 0, 0, 0},
338         {RC(1.0) / RC(2.0), 0, 0, 0, 0},
339         {RC(1.0) / RC(2.0), 0, 0, 0, 0},
340         {RC(1.0),           0, 0, 0, 0},
341         {RC(1.0),           0, 0, 0, 0}
342     },
343                     Af[5][5] = {{0, 0, 0, 0, 0}, {RC(1.0) / RC(2.0), 0, 0, 0, 0}, {RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), 0, 0, 0}, {RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), RC(1.0) / RC(2.0), 0, 0}, {RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), 0}}, bsb[5] = {RC(1.0) / RC(2.0), 0, 0, 0, RC(1.0) / RC(2.0)}, bf[5] = {RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), RC(1.0) / RC(4.0), 0};
344     const PetscInt rsb[5] = {0, 0, 2, 0, 4};
345     PetscCall(TSMPRKRegister(TSMPRKP2, 2, 5, 1, 1, &Asb[0][0], bsb, NULL, rsb, NULL, NULL, NULL, NULL, &Af[0][0], bf, NULL));
346   }
347 
348   {
349     const PetscReal Asb[10][10] =
350       {
351         {0,                  0, 0, 0, 0,                  0,                 0, 0, 0, 0},
352         {RC(1.0) / RC(4.0),  0, 0, 0, 0,                  0,                 0, 0, 0, 0},
353         {RC(1.0) / RC(4.0),  0, 0, 0, 0,                  0,                 0, 0, 0, 0},
354         {RC(1.0) / RC(2.0),  0, 0, 0, 0,                  0,                 0, 0, 0, 0},
355         {RC(1.0) / RC(2.0),  0, 0, 0, 0,                  0,                 0, 0, 0, 0},
356         {RC(-1.0) / RC(6.0), 0, 0, 0, RC(2.0) / RC(3.0),  0,                 0, 0, 0, 0},
357         {RC(1.0) / RC(12.0), 0, 0, 0, RC(1.0) / RC(6.0),  RC(1.0) / RC(2.0), 0, 0, 0, 0},
358         {RC(1.0) / RC(12.0), 0, 0, 0, RC(1.0) / RC(6.0),  RC(1.0) / RC(2.0), 0, 0, 0, 0},
359         {RC(1.0) / RC(3.0),  0, 0, 0, RC(-1.0) / RC(3.0), RC(1.0),           0, 0, 0, 0},
360         {RC(1.0) / RC(3.0),  0, 0, 0, RC(-1.0) / RC(3.0), RC(1.0),           0, 0, 0, 0}
361     },
362                     Af[10][10] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {RC(1.0) / RC(4.0), 0, 0, 0, 0, 0, 0, 0, 0, 0}, {RC(-1.0) / RC(12.0), RC(1.0) / RC(3.0), 0, 0, 0, 0, 0, 0, 0, 0}, {RC(1.0) / RC(6.0), RC(-1.0) / RC(6.0), RC(1.0) / RC(2.0), 0, 0, 0, 0, 0, 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, 0, 0, 0, 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, 0, 0, 0, 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, RC(1.0) / RC(4.0), 0, 0, 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, RC(-1.0) / RC(12.0), RC(1.0) / RC(3.0), 0, 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, RC(1.0) / RC(6.0), RC(-1.0) / RC(6.0), RC(1.0) / RC(2.0), 0, 0}, {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0}}, bsb[10] = {RC(1.0) / RC(6.0), 0, 0, 0, RC(1.0) / RC(3.0), RC(1.0) / RC(3.0), 0, 0, 0, RC(1.0) / RC(6.0)}, bf[10] = {RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0, RC(1.0) / RC(12.0), RC(1.0) / RC(6.0), RC(1.0) / RC(6.0), RC(1.0) / RC(12.0), 0};
363     const PetscInt rsb[10] = {0, 0, 2, 0, 4, 0, 0, 7, 0, 9};
364     PetscCall(TSMPRKRegister(TSMPRKP3, 3, 5, 2, 1, &Asb[0][0], bsb, NULL, rsb, NULL, NULL, NULL, NULL, &Af[0][0], bf, NULL));
365   }
366 #undef RC
367   PetscFunctionReturn(PETSC_SUCCESS);
368 }
369 
370 /*@C
371   TSMPRKRegisterDestroy - Frees the list of schemes that were registered by `TSMPRKRegister()`.
372 
373   Not Collective
374 
375   Level: advanced
376 
377 .seealso: [](ch_ts), `TSMPRK`, `TSMPRKRegister()`, `TSMPRKRegisterAll()`
378 @*/
379 PetscErrorCode TSMPRKRegisterDestroy(void)
380 {
381   MPRKTableauLink link;
382 
383   PetscFunctionBegin;
384   while ((link = MPRKTableauList)) {
385     MPRKTableau t   = &link->tab;
386     MPRKTableauList = link->next;
387     PetscCall(PetscFree3(t->Asb, t->bsb, t->csb));
388     PetscCall(PetscFree3(t->Amb, t->bmb, t->cmb));
389     PetscCall(PetscFree3(t->Af, t->bf, t->cf));
390     PetscCall(PetscFree(t->rsb));
391     PetscCall(PetscFree(t->rmb));
392     PetscCall(PetscFree(t->name));
393     PetscCall(PetscFree(link));
394   }
395   TSMPRKRegisterAllCalled = PETSC_FALSE;
396   PetscFunctionReturn(PETSC_SUCCESS);
397 }
398 
399 /*@C
400   TSMPRKInitializePackage - This function initializes everything in the `TSMPRK` package. It is called
401   from `PetscDLLibraryRegister()` when using dynamic libraries, and on the first call to `TSCreate_MPRK()`
402   when using static libraries.
403 
404   Level: developer
405 
406 .seealso: [](ch_ts), `TSMPRK`, `PetscInitialize()`
407 @*/
408 PetscErrorCode TSMPRKInitializePackage(void)
409 {
410   PetscFunctionBegin;
411   if (TSMPRKPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
412   TSMPRKPackageInitialized = PETSC_TRUE;
413   PetscCall(TSMPRKRegisterAll());
414   PetscCall(PetscRegisterFinalize(TSMPRKFinalizePackage));
415   PetscFunctionReturn(PETSC_SUCCESS);
416 }
417 
418 /*@C
419   TSMPRKFinalizePackage - This function destroys everything in the `TSMPRK` package. It is
420   called from `PetscFinalize()`.
421 
422   Level: developer
423 
424 .seealso: [](ch_ts), `TSMPRK`, `PetscFinalize()`
425 @*/
426 PetscErrorCode TSMPRKFinalizePackage(void)
427 {
428   PetscFunctionBegin;
429   TSMPRKPackageInitialized = PETSC_FALSE;
430   PetscCall(TSMPRKRegisterDestroy());
431   PetscFunctionReturn(PETSC_SUCCESS);
432 }
433 
434 /*@C
435   TSMPRKRegister - register a `TSMPRK` scheme by providing the entries in the Butcher tableau
436 
437   Not Collective, but the same schemes should be registered on all processes on which they will be used
438 
439   Input Parameters:
440 + name   - identifier for method
441 . order  - approximation order of method
442 . sbase  - number of stages in the base methods
443 . ratio1 - stepsize ratio at 1st level (e.g. slow/medium)
444 . ratio2 - stepsize ratio at 2nd level (e.g. medium/fast)
445 . Asb    - stage coefficients for slow components(dimension s*s, row-major)
446 . bsb    - step completion table for slow components(dimension s)
447 . csb    - abscissa for slow components(dimension s)
448 . rsb    - array of flags for repeated stages for slow components (dimension s)
449 . Amb    - stage coefficients for medium components(dimension s*s, row-major)
450 . bmb    - step completion table for medium components(dimension s)
451 . cmb    - abscissa for medium components(dimension s)
452 . rmb    - array of flags for repeated stages for medium components (dimension s)
453 . Af     - stage coefficients for fast components(dimension s*s, row-major)
454 . bf     - step completion table for fast components(dimension s)
455 - cf     - abscissa for fast components(dimension s)
456 
457   Level: advanced
458 
459   Note:
460   Several `TSMPRK` methods are provided, this function is only needed to create new methods.
461 
462 .seealso: [](ch_ts), `TSMPRK`
463 @*/
464 PetscErrorCode TSMPRKRegister(TSMPRKType name, PetscInt order, PetscInt sbase, PetscInt ratio1, PetscInt ratio2, const PetscReal Asb[], const PetscReal bsb[], const PetscReal csb[], const PetscInt rsb[], const PetscReal Amb[], const PetscReal bmb[], const PetscReal cmb[], const PetscInt rmb[], const PetscReal Af[], const PetscReal bf[], const PetscReal cf[])
465 {
466   MPRKTableauLink link;
467   MPRKTableau     t;
468   PetscInt        s, i, j;
469 
470   PetscFunctionBegin;
471   PetscAssertPointer(name, 1);
472   PetscAssertPointer(Asb, 6);
473   if (bsb) PetscAssertPointer(bsb, 7);
474   if (csb) PetscAssertPointer(csb, 8);
475   if (rsb) PetscAssertPointer(rsb, 9);
476   if (Amb) PetscAssertPointer(Amb, 10);
477   if (bmb) PetscAssertPointer(bmb, 11);
478   if (cmb) PetscAssertPointer(cmb, 12);
479   if (rmb) PetscAssertPointer(rmb, 13);
480   PetscAssertPointer(Af, 14);
481   if (bf) PetscAssertPointer(bf, 15);
482   if (cf) PetscAssertPointer(cf, 16);
483 
484   PetscCall(PetscNew(&link));
485   t = &link->tab;
486 
487   PetscCall(PetscStrallocpy(name, &t->name));
488   s        = sbase * ratio1 * ratio2; /*  this is the dimension of the matrices below */
489   t->order = order;
490   t->sbase = sbase;
491   t->s     = s;
492   t->np    = 2;
493 
494   PetscCall(PetscMalloc3(s * s, &t->Af, s, &t->bf, s, &t->cf));
495   PetscCall(PetscArraycpy(t->Af, Af, s * s));
496   if (bf) {
497     PetscCall(PetscArraycpy(t->bf, bf, s));
498   } else
499     for (i = 0; i < s; i++) t->bf[i] = Af[(s - 1) * s + i];
500   if (cf) {
501     PetscCall(PetscArraycpy(t->cf, cf, s));
502   } else {
503     for (i = 0; i < s; i++)
504       for (j = 0, t->cf[i] = 0; j < s; j++) t->cf[i] += Af[i * s + j];
505   }
506 
507   if (Amb) {
508     t->np = 3;
509     PetscCall(PetscMalloc3(s * s, &t->Amb, s, &t->bmb, s, &t->cmb));
510     PetscCall(PetscArraycpy(t->Amb, Amb, s * s));
511     if (bmb) {
512       PetscCall(PetscArraycpy(t->bmb, bmb, s));
513     } else {
514       for (i = 0; i < s; i++) t->bmb[i] = Amb[(s - 1) * s + i];
515     }
516     if (cmb) {
517       PetscCall(PetscArraycpy(t->cmb, cmb, s));
518     } else {
519       for (i = 0; i < s; i++)
520         for (j = 0, t->cmb[i] = 0; j < s; j++) t->cmb[i] += Amb[i * s + j];
521     }
522     if (rmb) {
523       PetscCall(PetscMalloc1(s, &t->rmb));
524       PetscCall(PetscArraycpy(t->rmb, rmb, s));
525     } else {
526       PetscCall(PetscCalloc1(s, &t->rmb));
527     }
528   }
529 
530   PetscCall(PetscMalloc3(s * s, &t->Asb, s, &t->bsb, s, &t->csb));
531   PetscCall(PetscArraycpy(t->Asb, Asb, s * s));
532   if (bsb) {
533     PetscCall(PetscArraycpy(t->bsb, bsb, s));
534   } else
535     for (i = 0; i < s; i++) t->bsb[i] = Asb[(s - 1) * s + i];
536   if (csb) {
537     PetscCall(PetscArraycpy(t->csb, csb, s));
538   } else {
539     for (i = 0; i < s; i++)
540       for (j = 0, t->csb[i] = 0; j < s; j++) t->csb[i] += Asb[i * s + j];
541   }
542   if (rsb) {
543     PetscCall(PetscMalloc1(s, &t->rsb));
544     PetscCall(PetscArraycpy(t->rsb, rsb, s));
545   } else {
546     PetscCall(PetscCalloc1(s, &t->rsb));
547   }
548   link->next      = MPRKTableauList;
549   MPRKTableauList = link;
550   PetscFunctionReturn(PETSC_SUCCESS);
551 }
552 
553 static PetscErrorCode TSMPRKSetSplits(TS ts)
554 {
555   TS_MPRK    *mprk = (TS_MPRK *)ts->data;
556   MPRKTableau tab  = mprk->tableau;
557   DM          dm, subdm, newdm;
558 
559   PetscFunctionBegin;
560   PetscCall(TSRHSSplitGetSubTS(ts, "slow", &mprk->subts_slow));
561   PetscCall(TSRHSSplitGetSubTS(ts, "fast", &mprk->subts_fast));
562   PetscCheck(mprk->subts_slow && mprk->subts_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up the RHSFunctions for 'slow' and 'fast' components using TSRHSSplitSetRHSFunction() or calling TSSetRHSFunction() for each sub-TS");
563 
564   /* Only copy the DM */
565   PetscCall(TSGetDM(ts, &dm));
566 
567   PetscCall(TSRHSSplitGetSubTS(ts, "slowbuffer", &mprk->subts_slowbuffer));
568   if (!mprk->subts_slowbuffer) {
569     mprk->subts_slowbuffer = mprk->subts_slow;
570     mprk->subts_slow       = NULL;
571   }
572   if (mprk->subts_slow) {
573     PetscCall(DMClone(dm, &newdm));
574     PetscCall(TSGetDM(mprk->subts_slow, &subdm));
575     PetscCall(DMCopyDMTS(subdm, newdm));
576     PetscCall(DMCopyDMSNES(subdm, newdm));
577     PetscCall(TSSetDM(mprk->subts_slow, newdm));
578     PetscCall(DMDestroy(&newdm));
579   }
580   PetscCall(DMClone(dm, &newdm));
581   PetscCall(TSGetDM(mprk->subts_slowbuffer, &subdm));
582   PetscCall(DMCopyDMTS(subdm, newdm));
583   PetscCall(DMCopyDMSNES(subdm, newdm));
584   PetscCall(TSSetDM(mprk->subts_slowbuffer, newdm));
585   PetscCall(DMDestroy(&newdm));
586 
587   PetscCall(DMClone(dm, &newdm));
588   PetscCall(TSGetDM(mprk->subts_fast, &subdm));
589   PetscCall(DMCopyDMTS(subdm, newdm));
590   PetscCall(DMCopyDMSNES(subdm, newdm));
591   PetscCall(TSSetDM(mprk->subts_fast, newdm));
592   PetscCall(DMDestroy(&newdm));
593 
594   if (tab->np == 3) {
595     PetscCall(TSRHSSplitGetSubTS(ts, "medium", &mprk->subts_medium));
596     PetscCall(TSRHSSplitGetSubTS(ts, "mediumbuffer", &mprk->subts_mediumbuffer));
597     if (mprk->subts_medium && !mprk->subts_mediumbuffer) {
598       mprk->subts_mediumbuffer = mprk->subts_medium;
599       mprk->subts_medium       = NULL;
600     }
601     if (mprk->subts_medium) {
602       PetscCall(DMClone(dm, &newdm));
603       PetscCall(TSGetDM(mprk->subts_medium, &subdm));
604       PetscCall(DMCopyDMTS(subdm, newdm));
605       PetscCall(DMCopyDMSNES(subdm, newdm));
606       PetscCall(TSSetDM(mprk->subts_medium, newdm));
607       PetscCall(DMDestroy(&newdm));
608     }
609     PetscCall(DMClone(dm, &newdm));
610     PetscCall(TSGetDM(mprk->subts_mediumbuffer, &subdm));
611     PetscCall(DMCopyDMTS(subdm, newdm));
612     PetscCall(DMCopyDMSNES(subdm, newdm));
613     PetscCall(TSSetDM(mprk->subts_mediumbuffer, newdm));
614     PetscCall(DMDestroy(&newdm));
615   }
616   PetscFunctionReturn(PETSC_SUCCESS);
617 }
618 
619 /*
620  This if for nonsplit RHS MPRK
621  The step completion formula is
622 
623  x1 = x0 + h b^T YdotRHS
624 
625 */
626 static PetscErrorCode TSEvaluateStep_MPRK(TS ts, PetscInt order, Vec X, PetscBool *done)
627 {
628   TS_MPRK     *mprk = (TS_MPRK *)ts->data;
629   MPRKTableau  tab  = mprk->tableau;
630   PetscScalar *wf   = mprk->work_fast;
631   PetscReal    h    = ts->time_step;
632   PetscInt     s    = tab->s, j;
633 
634   PetscFunctionBegin;
635   for (j = 0; j < s; j++) wf[j] = h * tab->bf[j];
636   PetscCall(VecCopy(ts->vec_sol, X));
637   PetscCall(VecMAXPY(X, s, wf, mprk->YdotRHS));
638   PetscFunctionReturn(PETSC_SUCCESS);
639 }
640 
641 static PetscErrorCode TSStep_MPRK(TS ts)
642 {
643   TS_MPRK         *mprk = (TS_MPRK *)ts->data;
644   Vec             *Y = mprk->Y, *YdotRHS = mprk->YdotRHS, *YdotRHS_fast = mprk->YdotRHS_fast, *YdotRHS_slow = mprk->YdotRHS_slow, *YdotRHS_slowbuffer = mprk->YdotRHS_slowbuffer;
645   Vec              Yslow, Yslowbuffer, Yfast;
646   MPRKTableau      tab = mprk->tableau;
647   const PetscInt   s   = tab->s;
648   const PetscReal *Af = tab->Af, *cf = tab->cf, *Asb = tab->Asb, *csb = tab->csb;
649   PetscScalar     *wf = mprk->work_fast, *wsb = mprk->work_slowbuffer;
650   PetscInt         i, j;
651   PetscReal        next_time_step = ts->time_step, t = ts->ptime, h = ts->time_step;
652 
653   PetscFunctionBegin;
654   for (i = 0; i < s; i++) {
655     mprk->stage_time = t + h * cf[i];
656     PetscCall(TSPreStage(ts, mprk->stage_time));
657     PetscCall(VecCopy(ts->vec_sol, Y[i]));
658 
659     /* slow buffer region */
660     for (j = 0; j < i; j++) wsb[j] = h * Asb[i * s + j];
661     for (j = 0; j < i; j++) PetscCall(VecGetSubVector(YdotRHS[j], mprk->is_slowbuffer, &YdotRHS_slowbuffer[j]));
662     PetscCall(VecGetSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
663     PetscCall(VecMAXPY(Yslowbuffer, i, wsb, mprk->YdotRHS_slowbuffer));
664     PetscCall(VecRestoreSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
665     for (j = 0; j < i; j++) PetscCall(VecRestoreSubVector(YdotRHS[j], mprk->is_slowbuffer, &YdotRHS_slowbuffer[j]));
666     /* slow region */
667     if (mprk->is_slow) {
668       for (j = 0; j < i; j++) PetscCall(VecGetSubVector(YdotRHS[j], mprk->is_slow, &YdotRHS_slow[j]));
669       PetscCall(VecGetSubVector(Y[i], mprk->is_slow, &Yslow));
670       PetscCall(VecMAXPY(Yslow, i, wsb, mprk->YdotRHS_slow));
671       PetscCall(VecRestoreSubVector(Y[i], mprk->is_slow, &Yslow));
672       for (j = 0; j < i; j++) PetscCall(VecRestoreSubVector(YdotRHS[j], mprk->is_slow, &YdotRHS_slow[j]));
673     }
674 
675     /* fast region */
676     for (j = 0; j < i; j++) wf[j] = h * Af[i * s + j];
677     for (j = 0; j < i; j++) PetscCall(VecGetSubVector(YdotRHS[j], mprk->is_fast, &YdotRHS_fast[j]));
678     PetscCall(VecGetSubVector(Y[i], mprk->is_fast, &Yfast));
679     PetscCall(VecMAXPY(Yfast, i, wf, mprk->YdotRHS_fast));
680     PetscCall(VecRestoreSubVector(Y[i], mprk->is_fast, &Yfast));
681     for (j = 0; j < i; j++) PetscCall(VecRestoreSubVector(YdotRHS[j], mprk->is_fast, &YdotRHS_fast[j]));
682     if (tab->np == 3) {
683       Vec         *YdotRHS_medium = mprk->YdotRHS_medium, *YdotRHS_mediumbuffer = mprk->YdotRHS_mediumbuffer;
684       Vec          Ymedium, Ymediumbuffer;
685       PetscScalar *wmb = mprk->work_mediumbuffer;
686 
687       for (j = 0; j < i; j++) wmb[j] = h * tab->Amb[i * s + j];
688       /* medium region */
689       if (mprk->is_medium) {
690         for (j = 0; j < i; j++) PetscCall(VecGetSubVector(YdotRHS[j], mprk->is_medium, &YdotRHS_medium[j]));
691         PetscCall(VecGetSubVector(Y[i], mprk->is_medium, &Ymedium));
692         PetscCall(VecMAXPY(Ymedium, i, wmb, mprk->YdotRHS_medium));
693         PetscCall(VecRestoreSubVector(Y[i], mprk->is_medium, &Ymedium));
694         for (j = 0; j < i; j++) PetscCall(VecRestoreSubVector(YdotRHS[j], mprk->is_medium, &YdotRHS_medium[j]));
695       }
696       /* medium buffer region */
697       for (j = 0; j < i; j++) PetscCall(VecGetSubVector(YdotRHS[j], mprk->is_mediumbuffer, &YdotRHS_mediumbuffer[j]));
698       PetscCall(VecGetSubVector(Y[i], mprk->is_mediumbuffer, &Ymediumbuffer));
699       PetscCall(VecMAXPY(Ymediumbuffer, i, wmb, mprk->YdotRHS_mediumbuffer));
700       PetscCall(VecRestoreSubVector(Y[i], mprk->is_mediumbuffer, &Ymediumbuffer));
701       for (j = 0; j < i; j++) PetscCall(VecRestoreSubVector(YdotRHS[j], mprk->is_mediumbuffer, &YdotRHS_mediumbuffer[j]));
702     }
703     PetscCall(TSPostStage(ts, mprk->stage_time, i, Y));
704     /* compute the stage RHS by fast and slow tableau respectively */
705     PetscCall(TSComputeRHSFunction(ts, t + h * csb[i], Y[i], YdotRHS[i]));
706   }
707   PetscCall(TSEvaluateStep(ts, tab->order, ts->vec_sol, NULL));
708   ts->ptime += ts->time_step;
709   ts->time_step = next_time_step;
710   PetscFunctionReturn(PETSC_SUCCESS);
711 }
712 
713 /*
714  This if for the case when split RHS is used
715  The step completion formula is
716  x1 = x0 + h b^T YdotRHS
717 */
718 static PetscErrorCode TSEvaluateStep_MPRKSPLIT(TS ts, PetscInt order, Vec X, PetscBool *done)
719 {
720   TS_MPRK     *mprk = (TS_MPRK *)ts->data;
721   MPRKTableau  tab  = mprk->tableau;
722   Vec          Xslow, Xfast, Xslowbuffer; /* subvectors for slow and fast components in X respectively */
723   PetscScalar *wf = mprk->work_fast, *ws = mprk->work_slow, *wsb = mprk->work_slowbuffer;
724   PetscReal    h = ts->time_step;
725   PetscInt     s = tab->s, j, computedstages;
726 
727   PetscFunctionBegin;
728   PetscCall(VecCopy(ts->vec_sol, X));
729 
730   /* slow region */
731   if (mprk->is_slow) {
732     computedstages = 0;
733     for (j = 0; j < s; j++) {
734       if (tab->rsb[j]) ws[tab->rsb[j] - 1] += h * tab->bsb[j];
735       else ws[computedstages++] = h * tab->bsb[j];
736     }
737     PetscCall(VecGetSubVector(X, mprk->is_slow, &Xslow));
738     PetscCall(VecMAXPY(Xslow, computedstages, ws, mprk->YdotRHS_slow));
739     PetscCall(VecRestoreSubVector(X, mprk->is_slow, &Xslow));
740   }
741 
742   if (tab->np == 3 && mprk->is_medium) {
743     computedstages = 0;
744     for (j = 0; j < s; j++) {
745       if (tab->rmb[j]) wsb[computedstages - tab->sbase + (tab->rmb[j] - 1) % tab->sbase] += h * tab->bsb[j];
746       else wsb[computedstages++] = h * tab->bsb[j];
747     }
748     PetscCall(VecGetSubVector(X, mprk->is_slowbuffer, &Xslowbuffer));
749     PetscCall(VecMAXPY(Xslowbuffer, computedstages, wsb, mprk->YdotRHS_slowbuffer));
750     PetscCall(VecRestoreSubVector(X, mprk->is_slowbuffer, &Xslowbuffer));
751   } else {
752     /* slow buffer region */
753     for (j = 0; j < s; j++) wsb[j] = h * tab->bsb[j];
754     PetscCall(VecGetSubVector(X, mprk->is_slowbuffer, &Xslowbuffer));
755     PetscCall(VecMAXPY(Xslowbuffer, s, wsb, mprk->YdotRHS_slowbuffer));
756     PetscCall(VecRestoreSubVector(X, mprk->is_slowbuffer, &Xslowbuffer));
757   }
758   if (tab->np == 3) {
759     Vec          Xmedium, Xmediumbuffer;
760     PetscScalar *wm = mprk->work_medium, *wmb = mprk->work_mediumbuffer;
761     /* medium region and slow buffer region */
762     if (mprk->is_medium) {
763       computedstages = 0;
764       for (j = 0; j < s; j++) {
765         if (tab->rmb[j]) wm[computedstages - tab->sbase + (tab->rmb[j] - 1) % tab->sbase] += h * tab->bmb[j];
766         else wm[computedstages++] = h * tab->bmb[j];
767       }
768       PetscCall(VecGetSubVector(X, mprk->is_medium, &Xmedium));
769       PetscCall(VecMAXPY(Xmedium, computedstages, wm, mprk->YdotRHS_medium));
770       PetscCall(VecRestoreSubVector(X, mprk->is_medium, &Xmedium));
771     }
772     /* medium buffer region */
773     for (j = 0; j < s; j++) wmb[j] = h * tab->bmb[j];
774     PetscCall(VecGetSubVector(X, mprk->is_mediumbuffer, &Xmediumbuffer));
775     PetscCall(VecMAXPY(Xmediumbuffer, s, wmb, mprk->YdotRHS_mediumbuffer));
776     PetscCall(VecRestoreSubVector(X, mprk->is_mediumbuffer, &Xmediumbuffer));
777   }
778   /* fast region */
779   for (j = 0; j < s; j++) wf[j] = h * tab->bf[j];
780   PetscCall(VecGetSubVector(X, mprk->is_fast, &Xfast));
781   PetscCall(VecMAXPY(Xfast, s, wf, mprk->YdotRHS_fast));
782   PetscCall(VecRestoreSubVector(X, mprk->is_fast, &Xfast));
783   PetscFunctionReturn(PETSC_SUCCESS);
784 }
785 
786 static PetscErrorCode TSStep_MPRKSPLIT(TS ts)
787 {
788   TS_MPRK         *mprk = (TS_MPRK *)ts->data;
789   MPRKTableau      tab  = mprk->tableau;
790   Vec             *Y = mprk->Y, *YdotRHS_fast = mprk->YdotRHS_fast, *YdotRHS_slow = mprk->YdotRHS_slow, *YdotRHS_slowbuffer = mprk->YdotRHS_slowbuffer;
791   Vec              Yslow, Yslowbuffer, Yfast; /* subvectors for slow and fast components in Y[i] respectively */
792   PetscInt         s  = tab->s;
793   const PetscReal *Af = tab->Af, *cf = tab->cf, *Asb = tab->Asb, *csb = tab->csb;
794   PetscScalar     *wf = mprk->work_fast, *ws = mprk->work_slow, *wsb = mprk->work_slowbuffer;
795   PetscInt         i, j, computedstages;
796   PetscReal        next_time_step = ts->time_step, t = ts->ptime, h = ts->time_step;
797 
798   PetscFunctionBegin;
799   for (i = 0; i < s; i++) {
800     mprk->stage_time = t + h * cf[i];
801     PetscCall(TSPreStage(ts, mprk->stage_time));
802     /* calculate the stage value for fast and slow components respectively */
803     PetscCall(VecCopy(ts->vec_sol, Y[i]));
804     for (j = 0; j < i; j++) wsb[j] = h * Asb[i * s + j];
805 
806     /* slow buffer region */
807     if (tab->np == 3 && mprk->is_medium) {
808       if (tab->rmb[i]) {
809         PetscCall(VecGetSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
810         PetscCall(VecISCopy(Y[tab->rmb[i] - 1], mprk->is_slowbuffer, SCATTER_REVERSE, Yslowbuffer));
811         PetscCall(VecRestoreSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
812       } else {
813         PetscScalar *wm = mprk->work_medium;
814         computedstages  = 0;
815         for (j = 0; j < i; j++) {
816           if (tab->rmb[j]) wm[computedstages - tab->sbase + (tab->rmb[j] - 1) % tab->sbase] += wsb[j];
817           else wm[computedstages++] = wsb[j];
818         }
819         PetscCall(VecGetSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
820         PetscCall(VecMAXPY(Yslowbuffer, computedstages, wm, YdotRHS_slowbuffer));
821         PetscCall(VecRestoreSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
822       }
823     } else {
824       PetscCall(VecGetSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
825       PetscCall(VecMAXPY(Yslowbuffer, i, wsb, YdotRHS_slowbuffer));
826       PetscCall(VecRestoreSubVector(Y[i], mprk->is_slowbuffer, &Yslowbuffer));
827     }
828 
829     /* slow region */
830     if (mprk->is_slow) {
831       if (tab->rsb[i]) { /* repeat previous stage */
832         PetscCall(VecGetSubVector(Y[i], mprk->is_slow, &Yslow));
833         PetscCall(VecISCopy(Y[tab->rsb[i] - 1], mprk->is_slow, SCATTER_REVERSE, Yslow));
834         PetscCall(VecRestoreSubVector(Y[i], mprk->is_slow, &Yslow));
835       } else {
836         computedstages = 0;
837         for (j = 0; j < i; j++) {
838           if (tab->rsb[j]) ws[tab->rsb[j] - 1] += wsb[j];
839           else ws[computedstages++] = wsb[j];
840         }
841         PetscCall(VecGetSubVector(Y[i], mprk->is_slow, &Yslow));
842         PetscCall(VecMAXPY(Yslow, computedstages, ws, YdotRHS_slow));
843         PetscCall(VecRestoreSubVector(Y[i], mprk->is_slow, &Yslow));
844         /* only depends on the slow buffer region */
845         PetscCall(TSComputeRHSFunction(mprk->subts_slow, t + h * csb[i], Y[i], YdotRHS_slow[computedstages]));
846       }
847     }
848 
849     /* fast region */
850     for (j = 0; j < i; j++) wf[j] = h * Af[i * s + j];
851     PetscCall(VecGetSubVector(Y[i], mprk->is_fast, &Yfast));
852     PetscCall(VecMAXPY(Yfast, i, wf, YdotRHS_fast));
853     PetscCall(VecRestoreSubVector(Y[i], mprk->is_fast, &Yfast));
854 
855     if (tab->np == 3) {
856       Vec             *YdotRHS_medium = mprk->YdotRHS_medium, *YdotRHS_mediumbuffer = mprk->YdotRHS_mediumbuffer;
857       Vec              Ymedium, Ymediumbuffer;
858       const PetscReal *Amb = tab->Amb, *cmb = tab->cmb;
859       PetscScalar     *wm = mprk->work_medium, *wmb = mprk->work_mediumbuffer;
860 
861       for (j = 0; j < i; j++) wmb[j] = h * Amb[i * s + j];
862       /* medium buffer region */
863       PetscCall(VecGetSubVector(Y[i], mprk->is_mediumbuffer, &Ymediumbuffer));
864       PetscCall(VecMAXPY(Ymediumbuffer, i, wmb, YdotRHS_mediumbuffer));
865       PetscCall(VecRestoreSubVector(Y[i], mprk->is_mediumbuffer, &Ymediumbuffer));
866       /* medium region */
867       if (mprk->is_medium) {
868         if (tab->rmb[i]) { /* repeat previous stage */
869           PetscCall(VecGetSubVector(Y[i], mprk->is_medium, &Ymedium));
870           PetscCall(VecISCopy(Y[tab->rmb[i] - 1], mprk->is_medium, SCATTER_REVERSE, Ymedium));
871           PetscCall(VecRestoreSubVector(Y[i], mprk->is_medium, &Ymedium));
872         } else {
873           computedstages = 0;
874           for (j = 0; j < i; j++) {
875             if (tab->rmb[j]) wm[computedstages - tab->sbase + (tab->rmb[j] - 1) % tab->sbase] += wmb[j];
876             else wm[computedstages++] = wmb[j];
877           }
878           PetscCall(VecGetSubVector(Y[i], mprk->is_medium, &Ymedium));
879           PetscCall(VecMAXPY(Ymedium, computedstages, wm, YdotRHS_medium));
880           PetscCall(VecRestoreSubVector(Y[i], mprk->is_medium, &Ymedium));
881           /* only depends on the medium buffer region */
882           PetscCall(TSComputeRHSFunction(mprk->subts_medium, t + h * cmb[i], Y[i], YdotRHS_medium[computedstages]));
883           /* must be computed after all regions are updated in Y */
884           PetscCall(TSComputeRHSFunction(mprk->subts_slowbuffer, t + h * csb[i], Y[i], YdotRHS_slowbuffer[computedstages]));
885         }
886       }
887       /* must be computed after fast region and slow region are updated in Y */
888       PetscCall(TSComputeRHSFunction(mprk->subts_mediumbuffer, t + h * cmb[i], Y[i], YdotRHS_mediumbuffer[i]));
889     }
890     if (!(tab->np == 3 && mprk->is_medium)) PetscCall(TSComputeRHSFunction(mprk->subts_slowbuffer, t + h * csb[i], Y[i], YdotRHS_slowbuffer[i]));
891     PetscCall(TSComputeRHSFunction(mprk->subts_fast, t + h * cf[i], Y[i], YdotRHS_fast[i]));
892   }
893 
894   PetscCall(TSEvaluateStep(ts, tab->order, ts->vec_sol, NULL));
895   ts->ptime += ts->time_step;
896   ts->time_step = next_time_step;
897   PetscFunctionReturn(PETSC_SUCCESS);
898 }
899 
900 static PetscErrorCode TSMPRKTableauReset(TS ts)
901 {
902   TS_MPRK    *mprk = (TS_MPRK *)ts->data;
903   MPRKTableau tab  = mprk->tableau;
904 
905   PetscFunctionBegin;
906   if (!tab) PetscFunctionReturn(PETSC_SUCCESS);
907   PetscCall(PetscFree(mprk->work_fast));
908   PetscCall(PetscFree(mprk->work_slow));
909   PetscCall(PetscFree(mprk->work_slowbuffer));
910   PetscCall(PetscFree(mprk->work_medium));
911   PetscCall(PetscFree(mprk->work_mediumbuffer));
912   PetscCall(VecDestroyVecs(tab->s, &mprk->Y));
913   if (ts->use_splitrhsfunction) {
914     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS_fast));
915     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS_slow));
916     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS_slowbuffer));
917     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS_medium));
918     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS_mediumbuffer));
919   } else {
920     PetscCall(VecDestroyVecs(tab->s, &mprk->YdotRHS));
921     if (mprk->is_slow) PetscCall(PetscFree(mprk->YdotRHS_slow));
922     PetscCall(PetscFree(mprk->YdotRHS_slowbuffer));
923     if (tab->np == 3) {
924       if (mprk->is_medium) PetscCall(PetscFree(mprk->YdotRHS_medium));
925       PetscCall(PetscFree(mprk->YdotRHS_mediumbuffer));
926     }
927     PetscCall(PetscFree(mprk->YdotRHS_fast));
928   }
929   PetscFunctionReturn(PETSC_SUCCESS);
930 }
931 
932 static PetscErrorCode TSReset_MPRK(TS ts)
933 {
934   PetscFunctionBegin;
935   PetscCall(TSMPRKTableauReset(ts));
936   PetscFunctionReturn(PETSC_SUCCESS);
937 }
938 
939 static PetscErrorCode DMCoarsenHook_TSMPRK(DM fine, DM coarse, void *ctx)
940 {
941   PetscFunctionBegin;
942   PetscFunctionReturn(PETSC_SUCCESS);
943 }
944 
945 static PetscErrorCode DMRestrictHook_TSMPRK(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
946 {
947   PetscFunctionBegin;
948   PetscFunctionReturn(PETSC_SUCCESS);
949 }
950 
951 static PetscErrorCode DMSubDomainHook_TSMPRK(DM dm, DM subdm, void *ctx)
952 {
953   PetscFunctionBegin;
954   PetscFunctionReturn(PETSC_SUCCESS);
955 }
956 
957 static PetscErrorCode DMSubDomainRestrictHook_TSMPRK(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
958 {
959   PetscFunctionBegin;
960   PetscFunctionReturn(PETSC_SUCCESS);
961 }
962 
963 static PetscErrorCode TSMPRKTableauSetUp(TS ts)
964 {
965   TS_MPRK    *mprk = (TS_MPRK *)ts->data;
966   MPRKTableau tab  = mprk->tableau;
967   Vec         YdotRHS_slow, YdotRHS_slowbuffer, YdotRHS_medium, YdotRHS_mediumbuffer, YdotRHS_fast;
968 
969   PetscFunctionBegin;
970   PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &mprk->Y));
971   if (mprk->is_slow) PetscCall(PetscMalloc1(tab->s, &mprk->work_slow));
972   PetscCall(PetscMalloc1(tab->s, &mprk->work_slowbuffer));
973   if (tab->np == 3) {
974     if (mprk->is_medium) PetscCall(PetscMalloc1(tab->s, &mprk->work_medium));
975     PetscCall(PetscMalloc1(tab->s, &mprk->work_mediumbuffer));
976   }
977   PetscCall(PetscMalloc1(tab->s, &mprk->work_fast));
978 
979   if (ts->use_splitrhsfunction) {
980     if (mprk->is_slow) {
981       PetscCall(VecGetSubVector(ts->vec_sol, mprk->is_slow, &YdotRHS_slow));
982       PetscCall(VecDuplicateVecs(YdotRHS_slow, tab->s, &mprk->YdotRHS_slow));
983       PetscCall(VecRestoreSubVector(ts->vec_sol, mprk->is_slow, &YdotRHS_slow));
984     }
985     PetscCall(VecGetSubVector(ts->vec_sol, mprk->is_slowbuffer, &YdotRHS_slowbuffer));
986     PetscCall(VecDuplicateVecs(YdotRHS_slowbuffer, tab->s, &mprk->YdotRHS_slowbuffer));
987     PetscCall(VecRestoreSubVector(ts->vec_sol, mprk->is_slowbuffer, &YdotRHS_slowbuffer));
988     if (tab->np == 3) {
989       if (mprk->is_medium) {
990         PetscCall(VecGetSubVector(ts->vec_sol, mprk->is_medium, &YdotRHS_medium));
991         PetscCall(VecDuplicateVecs(YdotRHS_medium, tab->s, &mprk->YdotRHS_medium));
992         PetscCall(VecRestoreSubVector(ts->vec_sol, mprk->is_medium, &YdotRHS_medium));
993       }
994       PetscCall(VecGetSubVector(ts->vec_sol, mprk->is_mediumbuffer, &YdotRHS_mediumbuffer));
995       PetscCall(VecDuplicateVecs(YdotRHS_mediumbuffer, tab->s, &mprk->YdotRHS_mediumbuffer));
996       PetscCall(VecRestoreSubVector(ts->vec_sol, mprk->is_mediumbuffer, &YdotRHS_mediumbuffer));
997     }
998     PetscCall(VecGetSubVector(ts->vec_sol, mprk->is_fast, &YdotRHS_fast));
999     PetscCall(VecDuplicateVecs(YdotRHS_fast, tab->s, &mprk->YdotRHS_fast));
1000     PetscCall(VecRestoreSubVector(ts->vec_sol, mprk->is_fast, &YdotRHS_fast));
1001   } else {
1002     PetscCall(VecDuplicateVecs(ts->vec_sol, tab->s, &mprk->YdotRHS));
1003     if (mprk->is_slow) PetscCall(PetscMalloc1(tab->s, &mprk->YdotRHS_slow));
1004     PetscCall(PetscMalloc1(tab->s, &mprk->YdotRHS_slowbuffer));
1005     if (tab->np == 3) {
1006       if (mprk->is_medium) PetscCall(PetscMalloc1(tab->s, &mprk->YdotRHS_medium));
1007       PetscCall(PetscMalloc1(tab->s, &mprk->YdotRHS_mediumbuffer));
1008     }
1009     PetscCall(PetscMalloc1(tab->s, &mprk->YdotRHS_fast));
1010   }
1011   PetscFunctionReturn(PETSC_SUCCESS);
1012 }
1013 
1014 static PetscErrorCode TSSetUp_MPRK(TS ts)
1015 {
1016   TS_MPRK    *mprk = (TS_MPRK *)ts->data;
1017   MPRKTableau tab  = mprk->tableau;
1018   DM          dm;
1019 
1020   PetscFunctionBegin;
1021   PetscCall(TSRHSSplitGetIS(ts, "slow", &mprk->is_slow));
1022   PetscCall(TSRHSSplitGetIS(ts, "fast", &mprk->is_fast));
1023   PetscCheck(mprk->is_slow && mprk->is_fast, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up RHSSplits with TSRHSSplitSetIS() using split names 'slow' and 'fast' respectively in order to use the method '%s'", tab->name);
1024 
1025   if (tab->np == 3) {
1026     PetscCall(TSRHSSplitGetIS(ts, "medium", &mprk->is_medium));
1027     PetscCheck(mprk->is_medium, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up RHSSplits with TSRHSSplitSetIS() using split names 'slow' and 'medium' and 'fast' respectively in order to use the method '%s'", tab->name);
1028     PetscCall(TSRHSSplitGetIS(ts, "mediumbuffer", &mprk->is_mediumbuffer));
1029     if (!mprk->is_mediumbuffer) { /* let medium buffer cover whole medium region */
1030       mprk->is_mediumbuffer = mprk->is_medium;
1031       mprk->is_medium       = NULL;
1032     }
1033   }
1034 
1035   /* If users do not provide buffer region settings, the solver will do them automatically, but with a performance penalty */
1036   PetscCall(TSRHSSplitGetIS(ts, "slowbuffer", &mprk->is_slowbuffer));
1037   if (!mprk->is_slowbuffer) { /* let slow buffer cover whole slow region */
1038     mprk->is_slowbuffer = mprk->is_slow;
1039     mprk->is_slow       = NULL;
1040   }
1041   PetscCall(TSCheckImplicitTerm(ts));
1042   PetscCall(TSMPRKTableauSetUp(ts));
1043   PetscCall(TSGetDM(ts, &dm));
1044   PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_TSMPRK, DMRestrictHook_TSMPRK, ts));
1045   PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_TSMPRK, DMSubDomainRestrictHook_TSMPRK, ts));
1046   if (ts->use_splitrhsfunction) {
1047     ts->ops->step         = TSStep_MPRKSPLIT;
1048     ts->ops->evaluatestep = TSEvaluateStep_MPRKSPLIT;
1049     PetscCall(TSMPRKSetSplits(ts));
1050   } else {
1051     ts->ops->step         = TSStep_MPRK;
1052     ts->ops->evaluatestep = TSEvaluateStep_MPRK;
1053   }
1054   PetscFunctionReturn(PETSC_SUCCESS);
1055 }
1056 
1057 static PetscErrorCode TSSetFromOptions_MPRK(TS ts, PetscOptionItems *PetscOptionsObject)
1058 {
1059   TS_MPRK *mprk = (TS_MPRK *)ts->data;
1060 
1061   PetscFunctionBegin;
1062   PetscOptionsHeadBegin(PetscOptionsObject, "PRK ODE solver options");
1063   {
1064     MPRKTableauLink link;
1065     PetscInt        count, choice;
1066     PetscBool       flg;
1067     const char    **namelist;
1068     for (link = MPRKTableauList, count = 0; link; link = link->next, count++)
1069       ;
1070     PetscCall(PetscMalloc1(count, (char ***)&namelist));
1071     for (link = MPRKTableauList, count = 0; link; link = link->next, count++) namelist[count] = link->tab.name;
1072     PetscCall(PetscOptionsEList("-ts_mprk_type", "Family of MPRK method", "TSMPRKSetType", (const char *const *)namelist, count, mprk->tableau->name, &choice, &flg));
1073     if (flg) PetscCall(TSMPRKSetType(ts, namelist[choice]));
1074     PetscCall(PetscFree(namelist));
1075   }
1076   PetscOptionsHeadEnd();
1077   PetscFunctionReturn(PETSC_SUCCESS);
1078 }
1079 
1080 static PetscErrorCode TSView_MPRK(TS ts, PetscViewer viewer)
1081 {
1082   TS_MPRK  *mprk = (TS_MPRK *)ts->data;
1083   PetscBool iascii;
1084 
1085   PetscFunctionBegin;
1086   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1087   if (iascii) {
1088     MPRKTableau tab = mprk->tableau;
1089     TSMPRKType  mprktype;
1090     char        fbuf[512];
1091     char        sbuf[512];
1092     PetscInt    i;
1093     PetscCall(TSMPRKGetType(ts, &mprktype));
1094     PetscCall(PetscViewerASCIIPrintf(viewer, "  MPRK type %s\n", mprktype));
1095     PetscCall(PetscViewerASCIIPrintf(viewer, "  Order: %" PetscInt_FMT "\n", tab->order));
1096 
1097     PetscCall(PetscFormatRealArray(fbuf, sizeof(fbuf), "% 8.6f", tab->s, tab->cf));
1098     PetscCall(PetscViewerASCIIPrintf(viewer, "  Abscissa cf = %s\n", fbuf));
1099     PetscCall(PetscViewerASCIIPrintf(viewer, "  Af = \n"));
1100     for (i = 0; i < tab->s; i++) {
1101       PetscCall(PetscFormatRealArray(fbuf, sizeof(fbuf), "% 8.6f", tab->s, &tab->Af[i * tab->s]));
1102       PetscCall(PetscViewerASCIIPrintf(viewer, "    %s\n", fbuf));
1103     }
1104     PetscCall(PetscFormatRealArray(fbuf, sizeof(fbuf), "% 8.6f", tab->s, tab->bf));
1105     PetscCall(PetscViewerASCIIPrintf(viewer, "  bf = %s\n", fbuf));
1106 
1107     PetscCall(PetscFormatRealArray(sbuf, sizeof(sbuf), "% 8.6f", tab->s, tab->csb));
1108     PetscCall(PetscViewerASCIIPrintf(viewer, "  Abscissa csb = %s\n", sbuf));
1109     PetscCall(PetscViewerASCIIPrintf(viewer, "  Asb = \n"));
1110     for (i = 0; i < tab->s; i++) {
1111       PetscCall(PetscFormatRealArray(sbuf, sizeof(sbuf), "% 8.6f", tab->s, &tab->Asb[i * tab->s]));
1112       PetscCall(PetscViewerASCIIPrintf(viewer, "    %s\n", sbuf));
1113     }
1114     PetscCall(PetscFormatRealArray(sbuf, sizeof(sbuf), "% 8.6f", tab->s, tab->bsb));
1115     PetscCall(PetscViewerASCIIPrintf(viewer, "  bsb = %s\n", sbuf));
1116 
1117     if (tab->np == 3) {
1118       char mbuf[512];
1119       PetscCall(PetscFormatRealArray(mbuf, sizeof(mbuf), "% 8.6f", tab->s, tab->cmb));
1120       PetscCall(PetscViewerASCIIPrintf(viewer, "  Abscissa cmb = %s\n", mbuf));
1121       PetscCall(PetscViewerASCIIPrintf(viewer, "  Amb = \n"));
1122       for (i = 0; i < tab->s; i++) {
1123         PetscCall(PetscFormatRealArray(mbuf, sizeof(mbuf), "% 8.6f", tab->s, &tab->Amb[i * tab->s]));
1124         PetscCall(PetscViewerASCIIPrintf(viewer, "    %s\n", mbuf));
1125       }
1126       PetscCall(PetscFormatRealArray(mbuf, sizeof(mbuf), "% 8.6f", tab->s, tab->bmb));
1127       PetscCall(PetscViewerASCIIPrintf(viewer, "  bmb = %s\n", mbuf));
1128     }
1129   }
1130   PetscFunctionReturn(PETSC_SUCCESS);
1131 }
1132 
1133 static PetscErrorCode TSLoad_MPRK(TS ts, PetscViewer viewer)
1134 {
1135   TSAdapt adapt;
1136 
1137   PetscFunctionBegin;
1138   PetscCall(TSGetAdapt(ts, &adapt));
1139   PetscCall(TSAdaptLoad(adapt, viewer));
1140   PetscFunctionReturn(PETSC_SUCCESS);
1141 }
1142 
1143 /*@C
1144   TSMPRKSetType - Set the type of `TSMPRK` scheme
1145 
1146   Not Collective
1147 
1148   Input Parameters:
1149 + ts       - timestepping context
1150 - mprktype - type of `TSMPRK` scheme
1151 
1152   Options Database Key:
1153 . -ts_mprk_type - <pm2,p2,p3> - select the specific scheme
1154 
1155   Level: intermediate
1156 
1157 .seealso: [](ch_ts), `TSMPRKGetType()`, `TSMPRK`, `TSMPRKType`
1158 @*/
1159 PetscErrorCode TSMPRKSetType(TS ts, TSMPRKType mprktype)
1160 {
1161   PetscFunctionBegin;
1162   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1163   PetscAssertPointer(mprktype, 2);
1164   PetscTryMethod(ts, "TSMPRKSetType_C", (TS, TSMPRKType), (ts, mprktype));
1165   PetscFunctionReturn(PETSC_SUCCESS);
1166 }
1167 
1168 /*@C
1169   TSMPRKGetType - Get the type of `TSMPRK` scheme
1170 
1171   Not Collective
1172 
1173   Input Parameter:
1174 . ts - timestepping context
1175 
1176   Output Parameter:
1177 . mprktype - type of `TSMPRK` scheme
1178 
1179   Level: intermediate
1180 
1181 .seealso: [](ch_ts), `TSMPRK`
1182 @*/
1183 PetscErrorCode TSMPRKGetType(TS ts, TSMPRKType *mprktype)
1184 {
1185   PetscFunctionBegin;
1186   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1187   PetscUseMethod(ts, "TSMPRKGetType_C", (TS, TSMPRKType *), (ts, mprktype));
1188   PetscFunctionReturn(PETSC_SUCCESS);
1189 }
1190 
1191 static PetscErrorCode TSMPRKGetType_MPRK(TS ts, TSMPRKType *mprktype)
1192 {
1193   TS_MPRK *mprk = (TS_MPRK *)ts->data;
1194 
1195   PetscFunctionBegin;
1196   *mprktype = mprk->tableau->name;
1197   PetscFunctionReturn(PETSC_SUCCESS);
1198 }
1199 
1200 static PetscErrorCode TSMPRKSetType_MPRK(TS ts, TSMPRKType mprktype)
1201 {
1202   TS_MPRK        *mprk = (TS_MPRK *)ts->data;
1203   PetscBool       match;
1204   MPRKTableauLink link;
1205 
1206   PetscFunctionBegin;
1207   if (mprk->tableau) {
1208     PetscCall(PetscStrcmp(mprk->tableau->name, mprktype, &match));
1209     if (match) PetscFunctionReturn(PETSC_SUCCESS);
1210   }
1211   for (link = MPRKTableauList; link; link = link->next) {
1212     PetscCall(PetscStrcmp(link->tab.name, mprktype, &match));
1213     if (match) {
1214       if (ts->setupcalled) PetscCall(TSMPRKTableauReset(ts));
1215       mprk->tableau = &link->tab;
1216       if (ts->setupcalled) PetscCall(TSMPRKTableauSetUp(ts));
1217       PetscFunctionReturn(PETSC_SUCCESS);
1218     }
1219   }
1220   SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", mprktype);
1221 }
1222 
1223 static PetscErrorCode TSGetStages_MPRK(TS ts, PetscInt *ns, Vec **Y)
1224 {
1225   TS_MPRK *mprk = (TS_MPRK *)ts->data;
1226 
1227   PetscFunctionBegin;
1228   *ns = mprk->tableau->s;
1229   if (Y) *Y = mprk->Y;
1230   PetscFunctionReturn(PETSC_SUCCESS);
1231 }
1232 
1233 static PetscErrorCode TSDestroy_MPRK(TS ts)
1234 {
1235   PetscFunctionBegin;
1236   PetscCall(TSReset_MPRK(ts));
1237   if (ts->dm) {
1238     PetscCall(DMCoarsenHookRemove(ts->dm, DMCoarsenHook_TSMPRK, DMRestrictHook_TSMPRK, ts));
1239     PetscCall(DMSubDomainHookRemove(ts->dm, DMSubDomainHook_TSMPRK, DMSubDomainRestrictHook_TSMPRK, ts));
1240   }
1241   PetscCall(PetscFree(ts->data));
1242   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSMPRKGetType_C", NULL));
1243   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSMPRKSetType_C", NULL));
1244   PetscFunctionReturn(PETSC_SUCCESS);
1245 }
1246 
1247 /*MC
1248       TSMPRK - ODE solver using Multirate Partitioned Runge-Kutta schemes
1249 
1250   The user should provide the right hand side of the equation using `TSSetRHSFunction()`.
1251 
1252   Level: beginner
1253 
1254   Note:
1255   The default is `TSMPRKPM2`, it can be changed with `TSMPRKSetType()` or -ts_mprk_type
1256 
1257 .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSMPRKSetType()`, `TSMPRKGetType()`, `TSMPRKType`, `TSMPRKRegister()`, `TSMPRKSetMultirateType()`
1258           `TSMPRKM2`, `TSMPRKM3`, `TSMPRKRFSMR3`, `TSMPRKRFSMR2`, `TSType`
1259 M*/
1260 PETSC_EXTERN PetscErrorCode TSCreate_MPRK(TS ts)
1261 {
1262   TS_MPRK *mprk;
1263 
1264   PetscFunctionBegin;
1265   PetscCall(TSMPRKInitializePackage());
1266 
1267   ts->ops->reset          = TSReset_MPRK;
1268   ts->ops->destroy        = TSDestroy_MPRK;
1269   ts->ops->view           = TSView_MPRK;
1270   ts->ops->load           = TSLoad_MPRK;
1271   ts->ops->setup          = TSSetUp_MPRK;
1272   ts->ops->step           = TSStep_MPRK;
1273   ts->ops->evaluatestep   = TSEvaluateStep_MPRK;
1274   ts->ops->setfromoptions = TSSetFromOptions_MPRK;
1275   ts->ops->getstages      = TSGetStages_MPRK;
1276 
1277   PetscCall(PetscNew(&mprk));
1278   ts->data = (void *)mprk;
1279 
1280   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSMPRKGetType_C", TSMPRKGetType_MPRK));
1281   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSMPRKSetType_C", TSMPRKSetType_MPRK));
1282 
1283   PetscCall(TSMPRKSetType(ts, TSMPRKDefault));
1284   PetscFunctionReturn(PETSC_SUCCESS);
1285 }
1286