xref: /petsc/src/ts/impls/explicit/rk/rk.c (revision 6a1e4597ed412e5fbe2cf99f1526a5ef35d9fc8a)
1 /*
2   Code for time stepping with the Runge-Kutta method
3 
4   Notes:
5   The general system is written as
6 
7   Udot = F(t,U)
8 
9 */
10 
11 #include <petsc/private/tsimpl.h>                /*I   "petscts.h"   I*/
12 #include <petscdm.h>
13 #include <../src/ts/impls/explicit/rk/rk.h>
14 #include <../src/ts/impls/explicit/rk/mrk.h>
15 
16 static TSRKType  TSRKDefault = TSRK3BS;
17 static PetscBool TSRKRegisterAllCalled;
18 static PetscBool TSRKPackageInitialized;
19 
20 static RKTableauLink RKTableauList;
21 
22 /*MC
23      TSRK1FE - First order forward Euler scheme.
24 
25      This method has one stage.
26 
27      Options database:
28 .     -ts_rk_type 1fe
29 
30      Level: advanced
31 
32 .seealso: TSRK, TSRKType, TSRKSetType()
33 M*/
34 /*MC
35      TSRK2A - Second order RK scheme.
36 
37      This method has two stages.
38 
39      Options database:
40 .     -ts_rk_type 2a
41 
42      Level: advanced
43 
44 .seealso: TSRK, TSRKType, TSRKSetType()
45 M*/
46 /*MC
47      TSRK3 - Third order RK scheme.
48 
49      This method has three stages.
50 
51      Options database:
52 .     -ts_rk_type 3
53 
54      Level: advanced
55 
56 .seealso: TSRK, TSRKType, TSRKSetType()
57 M*/
58 /*MC
59      TSRK3BS - Third order RK scheme of Bogacki-Shampine with 2nd order embedded method.
60 
61      This method has four stages with the First Same As Last (FSAL) property.
62 
63      Options database:
64 .     -ts_rk_type 3bs
65 
66      Level: advanced
67 
68      References: https://doi.org/10.1016/0893-9659(89)90079-7
69 
70 .seealso: TSRK, TSRKType, TSRKSetType()
71 M*/
72 /*MC
73      TSRK4 - Fourth order RK scheme.
74 
75      This is the classical Runge-Kutta method with four stages.
76 
77      Options database:
78 .     -ts_rk_type 4
79 
80      Level: advanced
81 
82 .seealso: TSRK, TSRKType, TSRKSetType()
83 M*/
84 /*MC
85      TSRK5F - Fifth order Fehlberg RK scheme with a 4th order embedded method.
86 
87      This method has six stages.
88 
89      Options database:
90 .     -ts_rk_type 5f
91 
92      Level: advanced
93 
94 .seealso: TSRK, TSRKType, TSRKSetType()
95 M*/
96 /*MC
97      TSRK5DP - Fifth order Dormand-Prince RK scheme with the 4th order embedded method.
98 
99      This method has seven stages with the First Same As Last (FSAL) property.
100 
101      Options database:
102 .     -ts_rk_type 5dp
103 
104      Level: advanced
105 
106      References: https://doi.org/10.1016/0771-050X(80)90013-3
107 
108 .seealso: TSRK, TSRKType, TSRKSetType()
109 M*/
110 /*MC
111      TSRK5BS - Fifth order Bogacki-Shampine RK scheme with 4th order embedded method.
112 
113      This method has eight stages with the First Same As Last (FSAL) property.
114 
115      Options database:
116 .     -ts_rk_type 5bs
117 
118      Level: advanced
119 
120      References: https://doi.org/10.1016/0898-1221(96)00141-1
121 
122 .seealso: TSRK, TSRKType, TSRKSetType()
123 M*/
124 
125 /*@C
126   TSRKRegisterAll - Registers all of the Runge-Kutta explicit methods in TSRK
127 
128   Not Collective, but should be called by all processes which will need the schemes to be registered
129 
130   Level: advanced
131 
132 .keywords: TS, TSRK, register, all
133 
134 .seealso:  TSRKRegisterDestroy()
135 @*/
136 PetscErrorCode TSRKRegisterAll(void)
137 {
138   PetscErrorCode ierr;
139 
140   PetscFunctionBegin;
141   if (TSRKRegisterAllCalled) PetscFunctionReturn(0);
142   TSRKRegisterAllCalled = PETSC_TRUE;
143 
144 #define RC PetscRealConstant
145   {
146     const PetscReal
147       A[1][1] = {{0}},
148       b[1]    = {RC(1.0)};
149     ierr = TSRKRegister(TSRK1FE,1,1,&A[0][0],b,NULL,NULL,0,NULL);CHKERRQ(ierr);
150   }
151   {
152     const PetscReal
153       A[2][2]   = {{0,0},
154                    {RC(1.0),0}},
155       b[2]      =  {RC(0.5),RC(0.5)},
156       bembed[2] =  {RC(1.0),0};
157     ierr = TSRKRegister(TSRK2A,2,2,&A[0][0],b,NULL,bembed,0,NULL);CHKERRQ(ierr);
158   }
159   {
160     const PetscReal
161       A[3][3] = {{0,0,0},
162                  {RC(2.0)/RC(3.0),0,0},
163                  {RC(-1.0)/RC(3.0),RC(1.0),0}},
164       b[3]    =  {RC(0.25),RC(0.5),RC(0.25)};
165     ierr = TSRKRegister(TSRK3,3,3,&A[0][0],b,NULL,NULL,0,NULL);CHKERRQ(ierr);
166   }
167   {
168     const PetscReal
169       A[4][4]   = {{0,0,0,0},
170                    {RC(1.0)/RC(2.0),0,0,0},
171                    {0,RC(3.0)/RC(4.0),0,0},
172                    {RC(2.0)/RC(9.0),RC(1.0)/RC(3.0),RC(4.0)/RC(9.0),0}},
173       b[4]      =  {RC(2.0)/RC(9.0),RC(1.0)/RC(3.0),RC(4.0)/RC(9.0),0},
174       bembed[4] =  {RC(7.0)/RC(24.0),RC(1.0)/RC(4.0),RC(1.0)/RC(3.0),RC(1.0)/RC(8.0)};
175     ierr = TSRKRegister(TSRK3BS,3,4,&A[0][0],b,NULL,bembed,0,NULL);CHKERRQ(ierr);
176   }
177   {
178     const PetscReal
179       A[4][4] = {{0,0,0,0},
180                  {RC(0.5),0,0,0},
181                  {0,RC(0.5),0,0},
182                  {0,0,RC(1.0),0}},
183       b[4]    =  {RC(1.0)/RC(6.0),RC(1.0)/RC(3.0),RC(1.0)/RC(3.0),RC(1.0)/RC(6.0)};
184     ierr = TSRKRegister(TSRK4,4,4,&A[0][0],b,NULL,NULL,0,NULL);CHKERRQ(ierr);
185   }
186   {
187     const PetscReal
188       A[6][6]   = {{0,0,0,0,0,0},
189                    {RC(0.25),0,0,0,0,0},
190                    {RC(3.0)/RC(32.0),RC(9.0)/RC(32.0),0,0,0,0},
191                    {RC(1932.0)/RC(2197.0),RC(-7200.0)/RC(2197.0),RC(7296.0)/RC(2197.0),0,0,0},
192                    {RC(439.0)/RC(216.0),RC(-8.0),RC(3680.0)/RC(513.0),RC(-845.0)/RC(4104.0),0,0},
193                    {RC(-8.0)/RC(27.0),RC(2.0),RC(-3544.0)/RC(2565.0),RC(1859.0)/RC(4104.0),RC(-11.0)/RC(40.0),0}},
194       b[6]      =  {RC(16.0)/RC(135.0),0,RC(6656.0)/RC(12825.0),RC(28561.0)/RC(56430.0),RC(-9.0)/RC(50.0),RC(2.0)/RC(55.0)},
195       bembed[6] =  {RC(25.0)/RC(216.0),0,RC(1408.0)/RC(2565.0),RC(2197.0)/RC(4104.0),RC(-1.0)/RC(5.0),0};
196     ierr = TSRKRegister(TSRK5F,5,6,&A[0][0],b,NULL,bembed,0,NULL);CHKERRQ(ierr);
197   }
198   {
199     const PetscReal
200       A[7][7]   = {{0,0,0,0,0,0,0},
201                    {RC(1.0)/RC(5.0),0,0,0,0,0,0},
202                    {RC(3.0)/RC(40.0),RC(9.0)/RC(40.0),0,0,0,0,0},
203                    {RC(44.0)/RC(45.0),RC(-56.0)/RC(15.0),RC(32.0)/RC(9.0),0,0,0,0},
204                    {RC(19372.0)/RC(6561.0),RC(-25360.0)/RC(2187.0),RC(64448.0)/RC(6561.0),RC(-212.0)/RC(729.0),0,0,0},
205                    {RC(9017.0)/RC(3168.0),RC(-355.0)/RC(33.0),RC(46732.0)/RC(5247.0),RC(49.0)/RC(176.0),RC(-5103.0)/RC(18656.0),0,0},
206                    {RC(35.0)/RC(384.0),0,RC(500.0)/RC(1113.0),RC(125.0)/RC(192.0),RC(-2187.0)/RC(6784.0),RC(11.0)/RC(84.0),0}},
207       b[7]      =  {RC(35.0)/RC(384.0),0,RC(500.0)/RC(1113.0),RC(125.0)/RC(192.0),RC(-2187.0)/RC(6784.0),RC(11.0)/RC(84.0),0},
208         bembed[7] =  {RC(5179.0)/RC(57600.0),0,RC(7571.0)/RC(16695.0),RC(393.0)/RC(640.0),RC(-92097.0)/RC(339200.0),RC(187.0)/RC(2100.0),RC(1.0)/RC(40.0)},
209         binterp[7][5] =  {{RC(1.0),RC(-4034104133.0)/RC(1410260304.0),RC(105330401.0)/RC(33982176.0),RC(-13107642775.0)/RC(11282082432.0),RC(6542295.0)/RC(470086768.0)},
210                     {0,0,0,0,0},
211                     {0,RC(132343189600.0)/RC(32700410799.0),RC(-833316000.0)/RC(131326951.0),RC(91412856700.0)/RC(32700410799.0),RC(-523383600.0)/RC(10900136933.0)},
212                     {0,RC(-115792950.0)/RC(29380423.0),RC(185270875.0)/RC(16991088.0),RC(-12653452475.0)/RC(1880347072.0),RC(98134425.0)/RC(235043384.0)},
213                     {0,RC(70805911779.0)/RC(24914598704.0),RC(-4531260609.0)/RC(600351776.0),RC(988140236175.0)/RC(199316789632.0),RC(-14307999165.0)/RC(24914598704.0)},
214                     {0,RC(-331320693.0)/RC(205662961.0),RC(31361737.0)/RC(7433601.0),RC(-2426908385.0)/RC(822651844.0),RC(97305120.0)/RC(205662961.0)},
215                     {0,RC(44764047.0)/RC(29380423.0),RC(-1532549.0)/RC(353981.0),RC(90730570.0)/RC(29380423.0),RC(-8293050.0)/RC(29380423.0)}};
216 
217         ierr = TSRKRegister(TSRK5DP,5,7,&A[0][0],b,NULL,bembed,5,binterp[0]);CHKERRQ(ierr);
218   }
219   {
220     const PetscReal
221       A[8][8]   = {{0,0,0,0,0,0,0,0},
222                    {RC(1.0)/RC(6.0),0,0,0,0,0,0,0},
223                    {RC(2.0)/RC(27.0),RC(4.0)/RC(27.0),0,0,0,0,0,0},
224                    {RC(183.0)/RC(1372.0),RC(-162.0)/RC(343.0),RC(1053.0)/RC(1372.0),0,0,0,0,0},
225                    {RC(68.0)/RC(297.0),RC(-4.0)/RC(11.0),RC(42.0)/RC(143.0),RC(1960.0)/RC(3861.0),0,0,0,0},
226                    {RC(597.0)/RC(22528.0),RC(81.0)/RC(352.0),RC(63099.0)/RC(585728.0),RC(58653.0)/RC(366080.0),RC(4617.0)/RC(20480.0),0,0,0},
227                    {RC(174197.0)/RC(959244.0),RC(-30942.0)/RC(79937.0),RC(8152137.0)/RC(19744439.0),RC(666106.0)/RC(1039181.0),RC(-29421.0)/RC(29068.0),RC(482048.0)/RC(414219.0),0,0},
228                    {RC(587.0)/RC(8064.0),0,RC(4440339.0)/RC(15491840.0),RC(24353.0)/RC(124800.0),RC(387.0)/RC(44800.0),RC(2152.0)/RC(5985.0),RC(7267.0)/RC(94080.0),0}},
229       b[8]      =  {RC(587.0)/RC(8064.0),0,RC(4440339.0)/RC(15491840.0),RC(24353.0)/RC(124800.0),RC(387.0)/RC(44800.0),RC(2152.0)/RC(5985.0),RC(7267.0)/RC(94080.0),0},
230       bembed[8] =  {RC(2479.0)/RC(34992.0),0,RC(123.0)/RC(416.0),RC(612941.0)/RC(3411720.0),RC(43.0)/RC(1440.0),RC(2272.0)/RC(6561.0),RC(79937.0)/RC(1113912.0),RC(3293.0)/RC(556956.0)};
231     ierr = TSRKRegister(TSRK5BS,5,8,&A[0][0],b,NULL,bembed,0,NULL);CHKERRQ(ierr);
232   }
233 #undef RC
234   PetscFunctionReturn(0);
235 }
236 
237 /*@C
238    TSRKRegisterDestroy - Frees the list of schemes that were registered by TSRKRegister().
239 
240    Not Collective
241 
242    Level: advanced
243 
244 .keywords: TSRK, register, destroy
245 .seealso: TSRKRegister(), TSRKRegisterAll()
246 @*/
247 PetscErrorCode TSRKRegisterDestroy(void)
248 {
249   PetscErrorCode ierr;
250   RKTableauLink  link;
251 
252   PetscFunctionBegin;
253   while ((link = RKTableauList)) {
254     RKTableau t = &link->tab;
255     RKTableauList = link->next;
256     ierr = PetscFree3(t->A,t->b,t->c);  CHKERRQ(ierr);
257     ierr = PetscFree (t->bembed);       CHKERRQ(ierr);
258     ierr = PetscFree (t->binterp);      CHKERRQ(ierr);
259     ierr = PetscFree (t->name);         CHKERRQ(ierr);
260     ierr = PetscFree (link);            CHKERRQ(ierr);
261   }
262   TSRKRegisterAllCalled = PETSC_FALSE;
263   PetscFunctionReturn(0);
264 }
265 
266 /*@C
267   TSRKInitializePackage - This function initializes everything in the TSRK package. It is called
268   from TSInitializePackage().
269 
270   Level: developer
271 
272 .keywords: TS, TSRK, initialize, package
273 .seealso: PetscInitialize()
274 @*/
275 PetscErrorCode TSRKInitializePackage(void)
276 {
277   PetscErrorCode ierr;
278 
279   PetscFunctionBegin;
280   if (TSRKPackageInitialized) PetscFunctionReturn(0);
281   TSRKPackageInitialized = PETSC_TRUE;
282   ierr = TSRKRegisterAll();CHKERRQ(ierr);
283   ierr = PetscRegisterFinalize(TSRKFinalizePackage);CHKERRQ(ierr);
284   PetscFunctionReturn(0);
285 }
286 
287 /*@C
288   TSRKFinalizePackage - This function destroys everything in the TSRK package. It is
289   called from PetscFinalize().
290 
291   Level: developer
292 
293 .keywords: Petsc, destroy, package
294 .seealso: PetscFinalize()
295 @*/
296 PetscErrorCode TSRKFinalizePackage(void)
297 {
298   PetscErrorCode ierr;
299 
300   PetscFunctionBegin;
301   TSRKPackageInitialized = PETSC_FALSE;
302   ierr = TSRKRegisterDestroy();CHKERRQ(ierr);
303   PetscFunctionReturn(0);
304 }
305 
306 /*@C
307    TSRKRegister - register an RK scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation
308 
309    Not Collective, but the same schemes should be registered on all processes on which they will be used
310 
311    Input Parameters:
312 +  name - identifier for method
313 .  order - approximation order of method
314 .  s - number of stages, this is the dimension of the matrices below
315 .  A - stage coefficients (dimension s*s, row-major)
316 .  b - step completion table (dimension s; NULL to use last row of A)
317 .  c - abscissa (dimension s; NULL to use row sums of A)
318 .  bembed - completion table for embedded method (dimension s; NULL if not available)
319 .  p - Order of the interpolation scheme, equal to the number of columns of binterp
320 -  binterp - Coefficients of the interpolation formula (dimension s*p; NULL to reuse b with p=1)
321 
322    Notes:
323    Several RK methods are provided, this function is only needed to create new methods.
324 
325    Level: advanced
326 
327 .keywords: TS, register
328 
329 .seealso: TSRK
330 @*/
331 PetscErrorCode TSRKRegister(TSRKType name,PetscInt order,PetscInt s,
332                             const PetscReal A[],const PetscReal b[],const PetscReal c[],
333                             const PetscReal bembed[],PetscInt p,const PetscReal binterp[])
334 {
335   PetscErrorCode  ierr;
336   RKTableauLink   link;
337   RKTableau       t;
338   PetscInt        i,j;
339 
340   PetscFunctionBegin;
341   PetscValidCharPointer(name,1);
342   PetscValidRealPointer(A,4);
343   if (b) PetscValidRealPointer(b,5);
344   if (c) PetscValidRealPointer(c,6);
345   if (bembed) PetscValidRealPointer(bembed,7);
346   if (binterp || p > 1) PetscValidRealPointer(binterp,9);
347 
348   ierr = TSRKInitializePackage();CHKERRQ(ierr);
349   ierr = PetscNew(&link);CHKERRQ(ierr);
350   t = &link->tab;
351 
352   ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
353   t->order = order;
354   t->s = s;
355   ierr = PetscMalloc3(s*s,&t->A,s,&t->b,s,&t->c);CHKERRQ(ierr);
356   ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr);
357   if (b)  { ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr); }
358   else for (i=0; i<s; i++) t->b[i] = A[(s-1)*s+i];
359   if (c)  { ierr = PetscMemcpy(t->c,c,s*sizeof(c[0]));CHKERRQ(ierr); }
360   else for (i=0; i<s; i++) for (j=0,t->c[i]=0; j<s; j++) t->c[i] += A[i*s+j];
361   t->FSAL = PETSC_TRUE;
362   for (i=0; i<s; i++) if (t->A[(s-1)*s+i] != t->b[i]) t->FSAL = PETSC_FALSE;
363 
364   if (bembed) {
365     ierr = PetscMalloc1(s,&t->bembed);CHKERRQ(ierr);
366     ierr = PetscMemcpy(t->bembed,bembed,s*sizeof(bembed[0]));CHKERRQ(ierr);
367   }
368 
369   if (!binterp) { p = 1; binterp = t->b; }
370   t->p = p;
371   ierr = PetscMalloc1(s*p,&t->binterp);CHKERRQ(ierr);
372   ierr = PetscMemcpy(t->binterp,binterp,s*p*sizeof(binterp[0]));CHKERRQ(ierr);
373 
374   link->next = RKTableauList;
375   RKTableauList = link;
376   PetscFunctionReturn(0);
377 }
378 
379 /*
380  This is for single-step RK method
381  The step completion formula is
382 
383  x1 = x0 + h b^T YdotRHS
384 
385  This function can be called before or after ts->vec_sol has been updated.
386  Suppose we have a completion formula (b) and an embedded formula (be) of different order.
387  We can write
388 
389  x1e = x0 + h be^T YdotRHS
390      = x1 - h b^T YdotRHS + h be^T YdotRHS
391      = x1 + h (be - b)^T YdotRHS
392 
393  so we can evaluate the method with different order even after the step has been optimistically completed.
394 */
395 static PetscErrorCode TSEvaluateStep_RK(TS ts,PetscInt order,Vec X,PetscBool *done)
396 {
397   TS_RK          *rk   = (TS_RK*)ts->data;
398   RKTableau      tab  = rk->tableau;
399   PetscScalar    *w    = rk->work;
400   PetscReal      h;
401   PetscInt       s    = tab->s,j;
402   PetscErrorCode ierr;
403 
404   PetscFunctionBegin;
405   switch (rk->status) {
406   case TS_STEP_INCOMPLETE:
407   case TS_STEP_PENDING:
408     h = ts->time_step; break;
409   case TS_STEP_COMPLETE:
410     h = ts->ptime - ts->ptime_prev; break;
411   default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus");
412   }
413   if (order == tab->order) {
414     if (rk->status == TS_STEP_INCOMPLETE) {
415       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
416       for (j=0; j<s; j++) w[j] = h*tab->b[j]/rk->dtratio;
417       ierr = VecMAXPY(X,s,w,rk->YdotRHS);CHKERRQ(ierr);
418     } else {ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);}
419     PetscFunctionReturn(0);
420   } else if (order == tab->order-1) {
421     if (!tab->bembed) goto unavailable;
422     if (rk->status == TS_STEP_INCOMPLETE) { /*Complete with the embedded method (be)*/
423       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
424       for (j=0; j<s; j++) w[j] = h*tab->bembed[j];
425       ierr = VecMAXPY(X,s,w,rk->YdotRHS);CHKERRQ(ierr);
426     } else {  /*Rollback and re-complete using (be-b) */
427       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
428       for (j=0; j<s; j++) w[j] = h*(tab->bembed[j] - tab->b[j]);
429       ierr = VecMAXPY(X,s,w,rk->YdotRHS);CHKERRQ(ierr);
430     }
431     if (done) *done = PETSC_TRUE;
432     PetscFunctionReturn(0);
433   }
434 unavailable:
435   if (done) *done = PETSC_FALSE;
436   else SETERRQ3(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"RK '%s' of order %D cannot evaluate step at order %D. Consider using -ts_adapt_type none or a different method that has an embedded estimate.",tab->name,tab->order,order);
437   PetscFunctionReturn(0);
438 }
439 
440 static PetscErrorCode TSForwardCostIntegral_RK(TS ts)
441 {
442   TS_RK           *rk = (TS_RK*)ts->data;
443   RKTableau       tab = rk->tableau;
444   const PetscInt  s = tab->s;
445   const PetscReal *b = tab->b,*c = tab->c;
446   Vec             *Y = rk->Y;
447   PetscInt        i;
448   PetscErrorCode  ierr;
449 
450   PetscFunctionBegin;
451   /* backup cost integral */
452   ierr = VecCopy(ts->vec_costintegral,rk->VecCostIntegral0);CHKERRQ(ierr);
453   for (i=s-1; i>=0; i--) {
454     /* Evolve ts->vec_costintegral to compute integrals */
455     ierr = TSComputeCostIntegrand(ts,rk->ptime+rk->time_step*c[i],Y[i],ts->vec_costintegrand);CHKERRQ(ierr);
456     ierr = VecAXPY(ts->vec_costintegral,rk->time_step*b[i],ts->vec_costintegrand);CHKERRQ(ierr);
457   }
458   PetscFunctionReturn(0);
459 }
460 
461 static PetscErrorCode TSAdjointCostIntegral_RK(TS ts)
462 {
463   TS_RK           *rk = (TS_RK*)ts->data;
464   RKTableau       tab = rk->tableau;
465   const PetscInt  s = tab->s;
466   const PetscReal *b = tab->b,*c = tab->c;
467   Vec             *Y = rk->Y;
468   PetscInt        i;
469   PetscErrorCode  ierr;
470 
471   PetscFunctionBegin;
472   for (i=s-1; i>=0; i--) {
473     /* Evolve ts->vec_costintegral to compute integrals */
474     ierr = TSComputeCostIntegrand(ts,ts->ptime+ts->time_step*(1.0-c[i]),Y[i],ts->vec_costintegrand);CHKERRQ(ierr);
475     ierr = VecAXPY(ts->vec_costintegral,-ts->time_step*b[i],ts->vec_costintegrand);CHKERRQ(ierr);
476   }
477   PetscFunctionReturn(0);
478 }
479 
480 static PetscErrorCode TSRollBack_RK(TS ts)
481 {
482   TS_RK           *rk = (TS_RK*)ts->data;
483   RKTableau       tab = rk->tableau;
484   const PetscInt  s  = tab->s;
485   const PetscReal *b = tab->b;
486   PetscScalar     *w = rk->work;
487   Vec             *YdotRHS = rk->YdotRHS;
488   PetscInt        j;
489   PetscReal       h;
490   PetscErrorCode  ierr;
491 
492   PetscFunctionBegin;
493   switch (rk->status) {
494   case TS_STEP_INCOMPLETE:
495   case TS_STEP_PENDING:
496     h = ts->time_step; break;
497   case TS_STEP_COMPLETE:
498     h = ts->ptime - ts->ptime_prev; break;
499   default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus");
500   }
501   for (j=0; j<s; j++) w[j] = -h*b[j];
502   ierr = VecMAXPY(ts->vec_sol,s,w,YdotRHS);CHKERRQ(ierr);
503   PetscFunctionReturn(0);
504 }
505 
506 static PetscErrorCode TSStep_RK(TS ts)
507 {
508   TS_RK           *rk  = (TS_RK*)ts->data;
509   RKTableau       tab  = rk->tableau;
510   const PetscInt  s = tab->s;
511   const PetscReal *A = tab->A,*c = tab->c;
512   PetscScalar     *w = rk->work;
513   Vec             *Y = rk->Y,*YdotRHS = rk->YdotRHS;
514   PetscBool       FSAL = tab->FSAL;
515   TSAdapt         adapt;
516   PetscInt        i,j;
517   PetscInt        rejections = 0;
518   PetscBool       stageok,accept = PETSC_TRUE;
519   PetscReal       next_time_step = ts->time_step;
520   PetscErrorCode  ierr;
521 
522   PetscFunctionBegin;
523   if (ts->steprollback || ts->steprestart) FSAL = PETSC_FALSE;
524   if (FSAL) { ierr = VecCopy(YdotRHS[s-1],YdotRHS[0]);CHKERRQ(ierr); }
525 
526   rk->status = TS_STEP_INCOMPLETE;
527   while (!ts->reason && rk->status != TS_STEP_COMPLETE) {
528     PetscReal t = ts->ptime;
529     PetscReal h = ts->time_step;
530     for (i=0; i<s; i++) {
531       rk->stage_time = t + h*c[i];
532       ierr = TSPreStage(ts,rk->stage_time); CHKERRQ(ierr);
533       ierr = VecCopy(ts->vec_sol,Y[i]);CHKERRQ(ierr);
534       for (j=0; j<i; j++) w[j] = h*A[i*s+j];
535       ierr = VecMAXPY(Y[i],i,w,YdotRHS);CHKERRQ(ierr);
536       ierr = TSPostStage(ts,rk->stage_time,i,Y); CHKERRQ(ierr);
537       ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
538       ierr = TSAdaptCheckStage(adapt,ts,rk->stage_time,Y[i],&stageok);CHKERRQ(ierr);
539       if (!stageok) goto reject_step;
540       if (FSAL && !i) continue;
541       ierr = TSComputeRHSFunction(ts,t+h*c[i],Y[i],YdotRHS[i]);CHKERRQ(ierr);
542     }
543 
544     rk->status = TS_STEP_INCOMPLETE;
545     ierr = TSEvaluateStep(ts,tab->order,ts->vec_sol,NULL);CHKERRQ(ierr);
546     rk->status = TS_STEP_PENDING;
547     ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
548     ierr = TSAdaptCandidatesClear(adapt);CHKERRQ(ierr);
549     ierr = TSAdaptCandidateAdd(adapt,tab->name,tab->order,1,tab->ccfl,(PetscReal)tab->s,PETSC_TRUE);CHKERRQ(ierr);
550     ierr = TSAdaptChoose(adapt,ts,ts->time_step,NULL,&next_time_step,&accept);CHKERRQ(ierr);
551     rk->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
552     if (!accept) { /* Roll back the current step */
553       ierr = TSRollBack_RK(ts);CHKERRQ(ierr);
554       ts->time_step = next_time_step;
555       goto reject_step;
556     }
557 
558     if (ts->costintegralfwd) { /* Save the info for the later use in cost integral evaluation */
559       rk->ptime     = ts->ptime;
560       rk->time_step = ts->time_step;
561     }
562 
563     ts->ptime += ts->time_step;
564     ts->time_step = next_time_step;
565     break;
566 
567     reject_step:
568     ts->reject++; accept = PETSC_FALSE;
569     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
570       ts->reason = TS_DIVERGED_STEP_REJECTED;
571       ierr = PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,rejections);CHKERRQ(ierr);
572     }
573   }
574   PetscFunctionReturn(0);
575 }
576 
577 static PetscErrorCode TSAdjointSetUp_RK(TS ts)
578 {
579   TS_RK          *rk  = (TS_RK*)ts->data;
580   RKTableau      tab = rk->tableau;
581   PetscInt       s   = tab->s;
582   PetscErrorCode ierr;
583 
584   PetscFunctionBegin;
585   if (ts->adjointsetupcalled++) PetscFunctionReturn(0);
586   ierr = VecDuplicateVecs(ts->vecs_sensi[0],s*ts->numcost,&rk->VecsDeltaLam);CHKERRQ(ierr);
587   ierr = VecDuplicateVecs(ts->vecs_sensi[0],ts->numcost,&rk->VecsSensiTemp);CHKERRQ(ierr);
588   if(ts->vecs_sensip) {
589     ierr = VecDuplicate(ts->vecs_sensip[0],&rk->VecDeltaMu);CHKERRQ(ierr);
590   }
591   PetscFunctionReturn(0);
592 }
593 
594 static PetscErrorCode TSAdjointStep_RK(TS ts)
595 {
596   TS_RK            *rk = (TS_RK*)ts->data;
597   RKTableau        tab = rk->tableau;
598   Mat              J;
599   const PetscInt   s = tab->s;
600   const PetscReal  *A = tab->A,*b = tab->b,*c = tab->c;
601   PetscScalar      *w = rk->work;
602   Vec              *Y = rk->Y,*VecsDeltaLam = rk->VecsDeltaLam,VecDeltaMu = rk->VecDeltaMu,*VecsSensiTemp = rk->VecsSensiTemp;
603   PetscInt         i,j,nadj;
604   PetscReal        t = ts->ptime;
605   PetscReal        h = ts->time_step,stage_time;
606   PetscBool        zero;
607   PetscErrorCode   ierr;
608 
609   PetscFunctionBegin;
610   rk->status = TS_STEP_INCOMPLETE;
611 
612   for (i=s-1; i>=0; i--) {
613     if (tab->FSAL && i == s-1) {
614       /* VecsDeltaLam[nadj*s+s-1] are initialized with zeros and the values never change.*/
615       continue;
616     }
617     stage_time = t + h*(1.0-c[i]);
618     zero = PETSC_FALSE;
619     ierr = TSGetRHSJacobian(ts,&J,NULL,NULL,NULL);CHKERRQ(ierr);
620     ierr = TSComputeRHSJacobian(ts,stage_time,Y[i],J,J);CHKERRQ(ierr);
621     if (ts->vec_costintegral) {
622       ierr = TSComputeDRDUFunction(ts,stage_time,Y[i],ts->vecs_drdu);CHKERRQ(ierr);
623     }
624     if (ts->vecs_sensip) {
625       ierr = TSComputeRHSJacobianP(ts,stage_time,Y[i],ts->Jacp);CHKERRQ(ierr); /* get f_p */
626       if (ts->vec_costintegral) {
627         ierr = TSComputeDRDPFunction(ts,stage_time,Y[i],ts->vecs_drdp);CHKERRQ(ierr);
628       }
629     }
630 
631     if (b[i] == 0 && i == s-1) zero = PETSC_TRUE;
632 
633     for (j=i+1; j<s; j++) w[j-i-1]  = -h*A[j*s+i]; /* coefficients for computing VecsSensiTemp */
634 
635     for (nadj=0; nadj<ts->numcost; nadj++) {
636       /* Stage values of lambda */
637       if (!zero) {
638         ierr = VecCopy(ts->vecs_sensi[nadj],VecsSensiTemp[nadj]);CHKERRQ(ierr); /* VecDeltaLam is an vec array of size s by numcost */
639         ierr = VecScale(VecsSensiTemp[nadj],-h*b[i]);CHKERRQ(ierr);
640         ierr = VecMAXPY(VecsSensiTemp[nadj],s-i-1,w,&VecsDeltaLam[nadj*s+i+1]);CHKERRQ(ierr);
641         ierr = MatMultTranspose(J,VecsSensiTemp[nadj],VecsDeltaLam[nadj*s+i]);CHKERRQ(ierr);
642       } else {
643         /* \sum_{j=i+1}^s a_{ji}*lambda_{s,j} */
644         ierr = VecSet(VecsSensiTemp[nadj],0);CHKERRQ(ierr);
645         ierr = VecMAXPY(VecsSensiTemp[nadj],s-i-1,w,&VecsDeltaLam[nadj*s+i+1]);CHKERRQ(ierr);
646         ierr = MatMultTranspose(J,VecsSensiTemp[nadj],VecsDeltaLam[nadj*s+i]);CHKERRQ(ierr);
647         ierr = VecScale(VecsDeltaLam[nadj*s+i],-h);CHKERRQ(ierr);
648       }
649       if (ts->vec_costintegral) {
650         ierr = VecAXPY(VecsDeltaLam[nadj*s+i],-h*b[i],ts->vecs_drdu[nadj]);CHKERRQ(ierr);
651       }
652 
653       /* Stage values of mu */
654       if (ts->vecs_sensip) {
655         if (!zero) {
656           ierr = MatMultTranspose(ts->Jacp,VecsSensiTemp[nadj],VecDeltaMu);CHKERRQ(ierr);
657         } else {
658           ierr = VecSet(VecDeltaMu,0);CHKERRQ(ierr);
659         }
660         if (ts->vec_costintegral) {
661           ierr = VecAXPY(VecDeltaMu,-h*b[i],ts->vecs_drdp[nadj]);CHKERRQ(ierr);
662         }
663         ierr = VecAXPY(ts->vecs_sensip[nadj],1.,VecDeltaMu);CHKERRQ(ierr); /* update sensip for each stage */
664       }
665     }
666   }
667 
668   for (j=0; j<s; j++) w[j] = 1.0;
669   for (nadj=0; nadj<ts->numcost; nadj++) { /* no need to do this for mu's */
670     ierr = VecMAXPY(ts->vecs_sensi[nadj],s,w,&VecsDeltaLam[nadj*s]);CHKERRQ(ierr);
671   }
672   rk->status = TS_STEP_COMPLETE;
673   PetscFunctionReturn(0);
674 }
675 
676 static PetscErrorCode TSInterpolate_RK(TS ts,PetscReal itime,Vec X)
677 {
678   TS_RK            *rk = (TS_RK*)ts->data;
679   PetscInt         s  = rk->tableau->s,p = rk->tableau->p,i,j;
680   PetscReal        h;
681   PetscReal        tt,t;
682   PetscScalar      *b;
683   const PetscReal  *B = rk->tableau->binterp;
684   PetscErrorCode   ierr;
685 
686   PetscFunctionBegin;
687   if (!B) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSRK %s does not have an interpolation formula",rk->tableau->name);
688 
689   switch (rk->status) {
690     case TS_STEP_INCOMPLETE:
691     case TS_STEP_PENDING:
692       h = ts->time_step;
693       t = (itime - ts->ptime)/h;
694       break;
695     case TS_STEP_COMPLETE:
696       h = ts->ptime - ts->ptime_prev;
697       t = (itime - ts->ptime)/h + 1; /* In the interval [0,1] */
698       break;
699     default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus");
700   }
701   ierr = PetscMalloc1(s,&b);CHKERRQ(ierr);
702   for (i=0; i<s; i++) b[i] = 0;
703   for (j=0,tt=t; j<p; j++,tt*=t) {
704     for (i=0; i<s; i++) {
705       b[i]  += h * B[i*p+j] * tt;
706     }
707   }
708   ierr = VecCopy(rk->Y[0],X);CHKERRQ(ierr);
709   ierr = VecMAXPY(X,s,b,rk->YdotRHS);CHKERRQ(ierr);
710   ierr = PetscFree(b);CHKERRQ(ierr);
711   PetscFunctionReturn(0);
712 }
713 
714 /*------------------------------------------------------------*/
715 
716 static PetscErrorCode TSRKTableauReset(TS ts)
717 {
718   TS_RK          *rk = (TS_RK*)ts->data;
719   RKTableau      tab = rk->tableau;
720   PetscErrorCode ierr;
721 
722   PetscFunctionBegin;
723   if (!tab) PetscFunctionReturn(0);
724   ierr = PetscFree(rk->work);CHKERRQ(ierr);
725   ierr = VecDestroyVecs(tab->s,&rk->Y);CHKERRQ(ierr);
726   ierr = VecDestroyVecs(tab->s,&rk->YdotRHS);CHKERRQ(ierr);
727   ierr = VecDestroyVecs(tab->s*ts->numcost,&rk->VecsDeltaLam);CHKERRQ(ierr);
728   ierr = VecDestroyVecs(ts->numcost,&rk->VecsSensiTemp);CHKERRQ(ierr);
729   ierr = VecDestroy(&rk->VecDeltaMu);CHKERRQ(ierr);
730   PetscFunctionReturn(0);
731 }
732 
733 static PetscErrorCode TSReset_RK(TS ts)
734 {
735   TS_RK         *rk = (TS_RK*)ts->data;
736   PetscErrorCode ierr;
737 
738   PetscFunctionBegin;
739   ierr = TSRKTableauReset(ts);CHKERRQ(ierr);
740   ierr = VecDestroy(&rk->VecCostIntegral0);CHKERRQ(ierr);
741   if (ts->use_splitrhsfunction) {
742     ierr = PetscTryMethod(ts,"TSReset_RK_MultirateSplit_C",(TS),(ts));CHKERRQ(ierr);
743   } else {
744     ierr = PetscTryMethod(ts,"TSReset_RK_MultirateNonsplit_C",(TS),(ts));CHKERRQ(ierr);
745   }
746   PetscFunctionReturn(0);
747 }
748 
749 static PetscErrorCode DMCoarsenHook_TSRK(DM fine,DM coarse,void *ctx)
750 {
751   PetscFunctionBegin;
752   PetscFunctionReturn(0);
753 }
754 
755 static PetscErrorCode DMRestrictHook_TSRK(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
756 {
757   PetscFunctionBegin;
758   PetscFunctionReturn(0);
759 }
760 
761 
762 static PetscErrorCode DMSubDomainHook_TSRK(DM dm,DM subdm,void *ctx)
763 {
764   PetscFunctionBegin;
765   PetscFunctionReturn(0);
766 }
767 
768 static PetscErrorCode DMSubDomainRestrictHook_TSRK(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
769 {
770 
771   PetscFunctionBegin;
772   PetscFunctionReturn(0);
773 }
774 /*
775 static PetscErrorCode RKSetAdjCoe(RKTableau tab)
776 {
777   PetscReal *A,*b;
778   PetscInt        s,i,j;
779   PetscErrorCode  ierr;
780 
781   PetscFunctionBegin;
782   s    = tab->s;
783   ierr = PetscMalloc2(s*s,&A,s,&b);CHKERRQ(ierr);
784 
785   for (i=0; i<s; i++)
786     for (j=0; j<s; j++) {
787       A[i*s+j] = (tab->b[s-1-i]==0) ? 0: -tab->A[s-1-i+(s-1-j)*s] * tab->b[s-1-j] / tab->b[s-1-i];
788       ierr = PetscPrintf(PETSC_COMM_WORLD,"Coefficients: A[%D][%D]=%.6f\n",i,j,A[i*s+j]);CHKERRQ(ierr);
789     }
790 
791   for (i=0; i<s; i++) b[i] = (tab->b[s-1-i]==0)? 0: -tab->b[s-1-i];
792 
793   ierr  = PetscMemcpy(tab->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr);
794   ierr  = PetscMemcpy(tab->b,b,s*sizeof(b[0]));CHKERRQ(ierr);
795   ierr  = PetscFree2(A,b);CHKERRQ(ierr);
796   PetscFunctionReturn(0);
797 }
798 */
799 
800 static PetscErrorCode TSRKTableauSetUp(TS ts)
801 {
802   TS_RK          *rk  = (TS_RK*)ts->data;
803   RKTableau      tab = rk->tableau;
804   PetscErrorCode ierr;
805 
806   PetscFunctionBegin;
807   ierr = PetscMalloc1(tab->s,&rk->work);CHKERRQ(ierr);
808   ierr = VecDuplicateVecs(ts->vec_sol,tab->s,&rk->Y);CHKERRQ(ierr);
809   ierr = VecDuplicateVecs(ts->vec_sol,tab->s,&rk->YdotRHS);CHKERRQ(ierr);
810   PetscFunctionReturn(0);
811 }
812 
813 static PetscErrorCode TSSetUp_RK(TS ts)
814 {
815   TS_RK          *rk = (TS_RK*)ts->data;
816   PetscErrorCode ierr;
817   DM             dm;
818 
819   PetscFunctionBegin;
820   ierr = TSCheckImplicitTerm(ts);CHKERRQ(ierr);
821   ierr = TSRKTableauSetUp(ts);CHKERRQ(ierr);
822   if (!rk->VecCostIntegral0 && ts->vec_costintegral && ts->costintegralfwd) { /* back up cost integral */
823     ierr = VecDuplicate(ts->vec_costintegral,&rk->VecCostIntegral0);CHKERRQ(ierr);
824   }
825   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
826   ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_TSRK,DMRestrictHook_TSRK,ts);CHKERRQ(ierr);
827   ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_TSRK,DMSubDomainRestrictHook_TSRK,ts);CHKERRQ(ierr);
828   if (ts->use_splitrhsfunction) {
829     ierr = PetscTryMethod(ts,"TSSetUp_RK_MultirateSplit_C",(TS),(ts));CHKERRQ(ierr);
830   } else {
831     ierr = PetscTryMethod(ts,"TSSetUp_RK_MultirateNonsplit_C",(TS),(ts));CHKERRQ(ierr);
832   }
833   PetscFunctionReturn(0);
834 }
835 
836 static PetscErrorCode TSSetFromOptions_RK(PetscOptionItems *PetscOptionsObject,TS ts)
837 {
838   TS_RK          *rk = (TS_RK*)ts->data;
839   PetscErrorCode ierr;
840 
841   PetscFunctionBegin;
842   ierr = PetscOptionsHead(PetscOptionsObject,"RK ODE solver options");CHKERRQ(ierr);
843   {
844     RKTableauLink link;
845     PetscInt      count,choice;
846     PetscBool     flg,use_multirate = PETSC_FALSE;
847     const char    **namelist;
848 
849     for (link=RKTableauList,count=0; link; link=link->next,count++) ;
850     ierr = PetscMalloc1(count,(char***)&namelist);CHKERRQ(ierr);
851     for (link=RKTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
852     ierr = PetscOptionsBool("-ts_rk_multirate","Use interpolation-based multirate RK method","TSRKSetMultirate",rk->use_multirate,&use_multirate,&flg);CHKERRQ(ierr);
853     if (flg) {
854       ierr = TSRKSetMultirate(ts,use_multirate);CHKERRQ(ierr);
855     }
856     ierr = PetscOptionsEList("-ts_rk_type","Family of RK method","TSRKSetType",(const char*const*)namelist,count,rk->tableau->name,&choice,&flg);CHKERRQ(ierr);
857     if (flg) {ierr = TSRKSetType(ts,namelist[choice]);CHKERRQ(ierr);}
858     ierr = PetscFree(namelist);CHKERRQ(ierr);
859   }
860   ierr = PetscOptionsTail();CHKERRQ(ierr);
861   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Multirate methods options","");CHKERRQ(ierr);
862   ierr = PetscOptionsInt("-ts_rk_dtratio","time step ratio between slow and fast","",rk->dtratio,&rk->dtratio,NULL);CHKERRQ(ierr);
863   ierr = PetscOptionsEnd();CHKERRQ(ierr);
864   PetscFunctionReturn(0);
865 }
866 
867 static PetscErrorCode TSView_RK(TS ts,PetscViewer viewer)
868 {
869   TS_RK          *rk = (TS_RK*)ts->data;
870   PetscBool      iascii;
871   PetscErrorCode ierr;
872 
873   PetscFunctionBegin;
874   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
875   if (iascii) {
876     RKTableau tab  = rk->tableau;
877     TSRKType  rktype;
878     char      buf[512];
879     ierr = TSRKGetType(ts,&rktype);CHKERRQ(ierr);
880     ierr = PetscViewerASCIIPrintf(viewer,"  RK type %s\n",rktype);CHKERRQ(ierr);
881     ierr = PetscViewerASCIIPrintf(viewer,"  Order: %D\n",tab->order);CHKERRQ(ierr);
882     ierr = PetscViewerASCIIPrintf(viewer,"  FSAL property: %s\n",tab->FSAL ? "yes" : "no");CHKERRQ(ierr);
883     ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",tab->s,tab->c);CHKERRQ(ierr);
884     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa c = %s\n",buf);CHKERRQ(ierr);
885   }
886   PetscFunctionReturn(0);
887 }
888 
889 static PetscErrorCode TSLoad_RK(TS ts,PetscViewer viewer)
890 {
891   PetscErrorCode ierr;
892   TSAdapt        adapt;
893 
894   PetscFunctionBegin;
895   ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
896   ierr = TSAdaptLoad(adapt,viewer);CHKERRQ(ierr);
897   PetscFunctionReturn(0);
898 }
899 
900 /*@C
901   TSRKSetType - Set the type of RK scheme
902 
903   Logically collective
904 
905   Input Parameter:
906 +  ts - timestepping context
907 -  rktype - type of RK-scheme
908 
909   Options Database:
910 .   -ts_rk_type - <1fe,2a,3,3bs,4,5f,5dp,5bs>
911 
912   Level: intermediate
913 
914 .seealso: TSRKGetType(), TSRK, TSRKType, TSRK1FE, TSRK2A, TSRK3, TSRK3BS, TSRK4, TSRK5F, TSRK5DP, TSRK5BS
915 @*/
916 PetscErrorCode TSRKSetType(TS ts,TSRKType rktype)
917 {
918   PetscErrorCode ierr;
919 
920   PetscFunctionBegin;
921   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
922   PetscValidCharPointer(rktype,2);
923   ierr = PetscTryMethod(ts,"TSRKSetType_C",(TS,TSRKType),(ts,rktype));CHKERRQ(ierr);
924   PetscFunctionReturn(0);
925 }
926 
927 /*@C
928   TSRKGetType - Get the type of RK scheme
929 
930   Logically collective
931 
932   Input Parameter:
933 .  ts - timestepping context
934 
935   Output Parameter:
936 .  rktype - type of RK-scheme
937 
938   Level: intermediate
939 
940 .seealso: TSRKGetType()
941 @*/
942 PetscErrorCode TSRKGetType(TS ts,TSRKType *rktype)
943 {
944   PetscErrorCode ierr;
945 
946   PetscFunctionBegin;
947   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
948   ierr = PetscUseMethod(ts,"TSRKGetType_C",(TS,TSRKType*),(ts,rktype));CHKERRQ(ierr);
949   PetscFunctionReturn(0);
950 }
951 
952 static PetscErrorCode TSRKGetType_RK(TS ts,TSRKType *rktype)
953 {
954   TS_RK *rk = (TS_RK*)ts->data;
955 
956   PetscFunctionBegin;
957   *rktype = rk->tableau->name;
958   PetscFunctionReturn(0);
959 }
960 
961 static PetscErrorCode TSRKSetType_RK(TS ts,TSRKType rktype)
962 {
963   TS_RK          *rk = (TS_RK*)ts->data;
964   PetscErrorCode ierr;
965   PetscBool      match;
966   RKTableauLink  link;
967 
968   PetscFunctionBegin;
969   if (rk->tableau) {
970     ierr = PetscStrcmp(rk->tableau->name,rktype,&match);CHKERRQ(ierr);
971     if (match) PetscFunctionReturn(0);
972   }
973   for (link = RKTableauList; link; link=link->next) {
974     ierr = PetscStrcmp(link->tab.name,rktype,&match);CHKERRQ(ierr);
975     if (match) {
976       if (ts->setupcalled) {ierr = TSRKTableauReset(ts);CHKERRQ(ierr);}
977       rk->tableau = &link->tab;
978       if (ts->setupcalled) {ierr = TSRKTableauSetUp(ts);CHKERRQ(ierr);}
979       ts->default_adapt_type = rk->tableau->bembed ? TSADAPTBASIC : TSADAPTNONE;
980       PetscFunctionReturn(0);
981     }
982   }
983   SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",rktype);
984   PetscFunctionReturn(0);
985 }
986 
987 static PetscErrorCode  TSGetStages_RK(TS ts,PetscInt *ns,Vec **Y)
988 {
989   TS_RK *rk = (TS_RK*)ts->data;
990 
991   PetscFunctionBegin;
992   if (ns) *ns = rk->tableau->s;
993   if (Y)   *Y = rk->Y;
994   PetscFunctionReturn(0);
995 }
996 
997 static PetscErrorCode TSDestroy_RK(TS ts)
998 {
999   PetscErrorCode ierr;
1000 
1001   PetscFunctionBegin;
1002   ierr = TSReset_RK(ts);CHKERRQ(ierr);
1003   if (ts->dm) {
1004     ierr = DMCoarsenHookRemove(ts->dm,DMCoarsenHook_TSRK,DMRestrictHook_TSRK,ts);CHKERRQ(ierr);
1005     ierr = DMSubDomainHookRemove(ts->dm,DMSubDomainHook_TSRK,DMSubDomainRestrictHook_TSRK,ts);CHKERRQ(ierr);
1006   }
1007   ierr = PetscFree(ts->data);CHKERRQ(ierr);
1008   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKGetType_C",NULL);CHKERRQ(ierr);
1009   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKSetType_C",NULL);CHKERRQ(ierr);
1010   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKSetMultirate_C",NULL);CHKERRQ(ierr);
1011   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKGetMultirate_C",NULL);CHKERRQ(ierr);
1012   PetscFunctionReturn(0);
1013 }
1014 
1015 /*@C
1016   TSRKSetMultirate - Use the interpolation-based multirate RK method
1017 
1018   Logically collective
1019 
1020   Input Parameter:
1021 +  ts - timestepping context
1022 -  use_multirate - PETSC_TRUE enables the multirate RK method, sets the basic method to be RK2A and sets the ratio between slow stepsize and fast stepsize to be 2
1023 
1024   Options Database:
1025 .   -ts_rk_multirate - <true,false>
1026 
1027   Notes:
1028   The multirate method requires interpolation. The default interpolation works for 1st- and 2nd- order RK, but not for high-order RKs except TSRK5DP which comes with the interpolation coeffcients (binterp).
1029 
1030   Level: intermediate
1031 
1032 .seealso: TSRKGetMultirate()
1033 @*/
1034 PetscErrorCode TSRKSetMultirate(TS ts,PetscBool use_multirate)
1035 {
1036   PetscErrorCode ierr;
1037 
1038   PetscFunctionBegin;
1039   ierr = PetscTryMethod(ts,"TSRKSetMultirate_C",(TS,PetscBool),(ts,use_multirate));CHKERRQ(ierr);
1040   PetscFunctionReturn(0);
1041 }
1042 
1043 /*@C
1044   TSRKGetMultirate - Gets whether to Use the interpolation-based multirate RK method
1045 
1046   Not collective
1047 
1048   Input Parameter:
1049 .  ts - timestepping context
1050 
1051   Output Parameter:
1052 .  use_multirate - PETSC_TRUE if the multirate RK method is enabled, PETSC_FALSE otherwise
1053 
1054   Level: intermediate
1055 
1056 .seealso: TSRKSetMultirate()
1057 @*/
1058 PetscErrorCode TSRKGetMultirate(TS ts,PetscBool *use_multirate)
1059 {
1060   PetscErrorCode ierr;
1061 
1062   PetscFunctionBegin;
1063   ierr = PetscUseMethod(ts,"TSRKGetMultirate_C",(TS,PetscBool*),(ts,use_multirate));CHKERRQ(ierr);
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 /*MC
1068       TSRK - ODE and DAE solver using Runge-Kutta schemes
1069 
1070   The user should provide the right hand side of the equation
1071   using TSSetRHSFunction().
1072 
1073   Notes:
1074   The default is TSRK3BS, it can be changed with TSRKSetType() or -ts_rk_type
1075 
1076   Level: beginner
1077 
1078 .seealso:  TSCreate(), TS, TSSetType(), TSRKSetType(), TSRKGetType(), TSRKSetFullyImplicit(), TSRK2D, TTSRK2E, TSRK3,
1079            TSRK4, TSRK5, TSRKPRSSP2, TSRKBPR3, TSRKType, TSRKRegister(), TSRKSetMultirate(), TSRKGetMultirate()
1080 
1081 M*/
1082 PETSC_EXTERN PetscErrorCode TSCreate_RK(TS ts)
1083 {
1084   TS_RK          *rk;
1085   PetscErrorCode ierr;
1086 
1087   PetscFunctionBegin;
1088   ierr = TSRKInitializePackage();CHKERRQ(ierr);
1089 
1090   ts->ops->reset          = TSReset_RK;
1091   ts->ops->destroy        = TSDestroy_RK;
1092   ts->ops->view           = TSView_RK;
1093   ts->ops->load           = TSLoad_RK;
1094   ts->ops->setup          = TSSetUp_RK;
1095   ts->ops->adjointsetup   = TSAdjointSetUp_RK;
1096   ts->ops->interpolate    = TSInterpolate_RK;
1097   ts->ops->step           = TSStep_RK;
1098   ts->ops->evaluatestep   = TSEvaluateStep_RK;
1099   ts->ops->rollback       = TSRollBack_RK;
1100   ts->ops->setfromoptions = TSSetFromOptions_RK;
1101   ts->ops->getstages      = TSGetStages_RK;
1102   ts->ops->adjointstep    = TSAdjointStep_RK;
1103 
1104   ts->ops->adjointintegral = TSAdjointCostIntegral_RK;
1105   ts->ops->forwardintegral = TSForwardCostIntegral_RK;
1106 
1107   ierr = PetscNewLog(ts,&rk);CHKERRQ(ierr);
1108   ts->data = (void*)rk;
1109 
1110   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKGetType_C",TSRKGetType_RK);CHKERRQ(ierr);
1111   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKSetType_C",TSRKSetType_RK);CHKERRQ(ierr);
1112   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKSetMultirate_C",TSRKSetMultirate_RK);CHKERRQ(ierr);
1113   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSRKGetMultirate_C",TSRKGetMultirate_RK);CHKERRQ(ierr);
1114 
1115   ierr = TSRKSetType(ts,TSRKDefault);CHKERRQ(ierr);
1116   rk->dtratio = 1;
1117   PetscFunctionReturn(0);
1118 }
1119