xref: /petsc/src/ts/impls/rosw/rosw.c (revision f73f8d2c34b175c91d916331f941e255591e9aaf)
1 /*
2   Code for timestepping with Rosenbrock W methods
3 
4   Notes:
5   The general system is written as
6 
7   G(t,X,Xdot) = F(t,X)
8 
9   where G represents the stiff part of the physics and F represents the non-stiff part.
10   This method is designed to be linearly implicit on G and can use an approximate and lagged Jacobian.
11 
12 */
13 #include <private/tsimpl.h>                /*I   "petscts.h"   I*/
14 
15 #include <../src/mat/blockinvert.h>
16 
17 static const TSRosWType TSRosWDefault = TSROSWRA34PW2;
18 static PetscBool TSRosWRegisterAllCalled;
19 static PetscBool TSRosWPackageInitialized;
20 
21 typedef struct _RosWTableau *RosWTableau;
22 struct _RosWTableau {
23   char      *name;
24   PetscInt  order;              /* Classical approximation order of the method */
25   PetscInt  s;                  /* Number of stages */
26   PetscInt  pinterp;            /* Interpolation order */
27   PetscReal *A;                 /* Propagation table, strictly lower triangular */
28   PetscReal *Gamma;             /* Stage table, lower triangular with nonzero diagonal */
29   PetscBool *GammaZeroDiag;     /* Diagonal entries that are zero in stage table Gamma, vector indicating explicit statages */
30   PetscReal *GammaExplicitCorr; /* Coefficients for correction terms needed for explicit stages in transformed variables*/
31   PetscReal *b;                 /* Step completion table */
32   PetscReal *bembed;            /* Step completion table for embedded method of order one less */
33   PetscReal *ASum;              /* Row sum of A */
34   PetscReal *GammaSum;          /* Row sum of Gamma, only needed for non-autonomous systems */
35   PetscReal *At;                /* Propagation table in transformed variables */
36   PetscReal *bt;                /* Step completion table in transformed variables */
37   PetscReal *bembedt;           /* Step completion table of order one less in transformed variables */
38   PetscReal *GammaInv;          /* Inverse of Gamma, used for transformed variables */
39   PetscReal ccfl;               /* Placeholder for CFL coefficient relative to forward Euler */
40   PetscReal *binterpt,*binterp; /* Dense output formula */
41 };
42 typedef struct _RosWTableauLink *RosWTableauLink;
43 struct _RosWTableauLink {
44   struct _RosWTableau tab;
45   RosWTableauLink next;
46 };
47 static RosWTableauLink RosWTableauList;
48 
49 typedef struct {
50   RosWTableau tableau;
51   Vec         *Y;               /* States computed during the step, used to complete the step */
52   Vec         Ydot;             /* Work vector holding Ydot during residual evaluation */
53   Vec         Ystage;           /* Work vector for the state value at each stage */
54   Vec         Zdot;             /* Ydot = Zdot + shift*Y */
55   Vec         Zstage;           /* Y = Zstage + Y */
56   PetscScalar *work;            /* Scalar work space of length number of stages, used to prepare VecMAXPY() */
57   PetscReal   shift;
58   PetscReal   stage_time;
59   PetscReal   stage_explicit;     /* Flag indicates that the current stage is explicit */
60   PetscBool   recompute_jacobian; /* Recompute the Jacobian at each stage, default is to freeze the Jacobian at the start of each step */
61   TSStepStatus status;
62 } TS_RosW;
63 
64 /*MC
65      TSROSWTHETA1 - One stage first order L-stable Rosenbrock-W scheme (aka theta method).
66 
67      Only an approximate Jacobian is needed.
68 
69      Level: intermediate
70 
71 .seealso: TSROSW
72 M*/
73 
74 /*MC
75      TSROSWTHETA2 - One stage second order A-stable Rosenbrock-W scheme (aka theta method).
76 
77      Only an approximate Jacobian is needed.
78 
79      Level: intermediate
80 
81 .seealso: TSROSW
82 M*/
83 
84 /*MC
85      TSROSW2M - Two stage second order L-stable Rosenbrock-W scheme.
86 
87      Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2P.
88 
89      Level: intermediate
90 
91 .seealso: TSROSW
92 M*/
93 
94 /*MC
95      TSROSW2P - Two stage second order L-stable Rosenbrock-W scheme.
96 
97      Only an approximate Jacobian is needed. By default, it is only recomputed once per step. This method is a reflection of TSROSW2M.
98 
99      Level: intermediate
100 
101 .seealso: TSROSW
102 M*/
103 
104 /*MC
105      TSROSWRA3PW - Three stage third order Rosenbrock-W scheme for PDAE of index 1.
106 
107      Only an approximate Jacobian is needed. By default, it is only recomputed once per step.
108 
109      This is strongly A-stable with R(infty) = 0.73. The embedded method of order 2 is strongly A-stable with R(infty) = 0.73.
110 
111      References:
112      Rang and Angermann, New Rosenbrock-W methods of order 3 for partial differential algebraic equations of index 1, 2005.
113 
114      Level: intermediate
115 
116 .seealso: TSROSW
117 M*/
118 
119 /*MC
120      TSROSWRA34PW2 - Four stage third order L-stable Rosenbrock-W scheme for PDAE of index 1.
121 
122      Only an approximate Jacobian is needed. By default, it is only recomputed once per step.
123 
124      This is strongly A-stable with R(infty) = 0. The embedded method of order 2 is strongly A-stable with R(infty) = 0.48.
125 
126      References:
127      Rang and Angermann, New Rosenbrock-W methods of order 3 for partial differential algebraic equations of index 1, 2005.
128 
129      Level: intermediate
130 
131 .seealso: TSROSW
132 M*/
133 
134 /*MC
135      TSROSWRODAS3 - Four stage third order L-stable Rosenbrock scheme
136 
137      By default, the Jacobian is only recomputed once per step.
138 
139      Both the third order and embedded second order methods are stiffly accurate and L-stable.
140 
141      References:
142      Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997.
143 
144      Level: intermediate
145 
146 .seealso: TSROSW, TSROSWSANDU3
147 M*/
148 
149 /*MC
150      TSROSWSANDU3 - Three stage third order L-stable Rosenbrock scheme
151 
152      By default, the Jacobian is only recomputed once per step.
153 
154      The third order method is L-stable, but not stiffly accurate.
155      The second order embedded method is strongly A-stable with R(infty) = 0.5.
156      The internal stages are L-stable.
157      This method is called ROS3 in the paper.
158 
159      References:
160      Sandu et al, Benchmarking stiff ODE solvers for atmospheric chemistry problems II, Rosenbrock solvers, 1997.
161 
162      Level: intermediate
163 
164 .seealso: TSROSW, TSROSWRODAS3
165 M*/
166 
167 /*MC
168      TSROSWASSP3P3S1C - A-stable Rosenbrock-W method with SSP explicit part, third order, three stages
169 
170      By default, the Jacobian is only recomputed once per step.
171 
172      A-stable SPP explicit order 3, 3 stages, CFL 1 (eff = 1/3)
173 
174      References:
175      Emil Constantinescu
176 
177      Level: intermediate
178 
179 .seealso: TSROSW, TSROSWLASSP3P4S2C, TSROSWLLSSP3P4S2C, SSP
180 M*/
181 
182 /*MC
183      TSROSWLASSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, three stages
184 
185      By default, the Jacobian is only recomputed once per step.
186 
187      L-stable (A-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2)
188 
189      References:
190      Emil Constantinescu
191 
192      Level: intermediate
193 
194 .seealso: TSROSW, TSROSWASSP3P3S1C, TSROSWLLSSP3P4S2C, TSSSP
195 M*/
196 
197 /*MC
198      TSROSWLLSSP3P4S2C - L-stable Rosenbrock-W method with SSP explicit part, third order, three stages
199 
200      By default, the Jacobian is only recomputed once per step.
201 
202      L-stable (L-stable embedded) SPP explicit order 3, 4 stages, CFL 2 (eff = 1/2)
203 
204      References:
205      Emil Constantinescu
206 
207      Level: intermediate
208 
209 .seealso: TSROSW, TSROSWASSP3P3S1C, TSROSWLASSP3P4S2C, TSSSP
210 M*/
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "TSRosWRegisterAll"
214 /*@C
215   TSRosWRegisterAll - Registers all of the additive Runge-Kutta implicit-explicit methods in TSRosW
216 
217   Not Collective, but should be called by all processes which will need the schemes to be registered
218 
219   Level: advanced
220 
221 .keywords: TS, TSRosW, register, all
222 
223 .seealso:  TSRosWRegisterDestroy()
224 @*/
225 PetscErrorCode TSRosWRegisterAll(void)
226 {
227   PetscErrorCode ierr;
228 
229   PetscFunctionBegin;
230   if (TSRosWRegisterAllCalled) PetscFunctionReturn(0);
231   TSRosWRegisterAllCalled = PETSC_TRUE;
232 
233   {
234     const PetscReal
235       A = 0,
236       Gamma = 1,
237       b = 1;
238     ierr = TSRosWRegister(TSROSWTHETA1,1,1,&A,&Gamma,&b,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
239   }
240 
241   {
242     const PetscReal
243       A= 0,
244       Gamma = 0.5,
245       b = 1;
246     ierr = TSRosWRegister(TSROSWTHETA2,2,1,&A,&Gamma,&b,PETSC_NULL,0,PETSC_NULL);CHKERRQ(ierr);
247   }
248 
249   {
250     const PetscReal g = 1. + 1./PetscSqrtReal(2.0);
251     const PetscReal
252       A[2][2] = {{0,0}, {1.,0}},
253       Gamma[2][2] = {{g,0}, {-2.*g,g}},
254       b[2] = {0.5,0.5},
255       b1[2] = {1.0,0.0};
256     ierr = TSRosWRegister(TSROSW2P,2,2,&A[0][0],&Gamma[0][0],b,b1,0,PETSC_NULL);CHKERRQ(ierr);
257   }
258   {
259     const PetscReal g = 1. - 1./PetscSqrtReal(2.0);
260     const PetscReal
261       A[2][2] = {{0,0}, {1.,0}},
262       Gamma[2][2] = {{g,0}, {-2.*g,g}},
263       b[2] = {0.5,0.5},
264       b1[2] = {1.0,0.0};
265     ierr = TSRosWRegister(TSROSW2M,2,2,&A[0][0],&Gamma[0][0],b,b1,0,PETSC_NULL);CHKERRQ(ierr);
266   }
267   {
268     const PetscReal g = 7.8867513459481287e-01;
269     const PetscReal
270       A[3][3] = {{0,0,0},
271                  {1.5773502691896257e+00,0,0},
272                  {0.5,0,0}},
273       Gamma[3][3] = {{g,0,0},
274                      {-1.5773502691896257e+00,g,0},
275                      {-6.7075317547305480e-01,-1.7075317547305482e-01,g}},
276       b[3] = {1.0566243270259355e-01,4.9038105676657971e-02,8.4529946162074843e-01},
277       b2[3] = {-1.7863279495408180e-01,1./3.,8.4529946162074843e-01};
278     ierr = TSRosWRegister(TSROSWRA3PW,3,3,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
279   }
280   {
281     const PetscReal g = 4.3586652150845900e-01;
282     const PetscReal
283       A[4][4] = {{0,0,0,0},
284                  {8.7173304301691801e-01,0,0,0},
285                  {8.4457060015369423e-01,-1.1299064236484185e-01,0,0},
286                  {0,0,1.,0}},
287       Gamma[4][4] = {{g,0,0,0},
288                      {-8.7173304301691801e-01,g,0,0},
289                      {-9.0338057013044082e-01,5.4180672388095326e-02,g,0},
290                      {2.4212380706095346e-01,-1.2232505839045147e+00,5.4526025533510214e-01,g}},
291         b[4] = {2.4212380706095346e-01,-1.2232505839045147e+00,1.5452602553351020e+00,4.3586652150845900e-01},
292           b2[4] = {3.7810903145819369e-01,-9.6042292212423178e-02,5.0000000000000000e-01,2.1793326075422950e-01},
293             binterpt[4][3]={{1.0564298455794094,-1.3864882699759573,0.5721822314575016},{2.296429974281067,-8.262611700275677,4.742931142090097},{-1.307599564525376,7.250979895056055,-4.398120075195578},{-1.045260255335102,2.398120075195581,-0.9169932983520199}};
294       ierr = TSRosWRegister(TSROSWRA34PW2,3,4,&A[0][0],&Gamma[0][0],b,b2,3,binterpt[0]);CHKERRQ(ierr);
295   }
296   {
297     const PetscReal g = 0.5;
298     const PetscReal
299       A[4][4] = {{0,0,0,0},
300                  {0,0,0,0},
301                  {1.,0,0,0},
302                  {0.75,-0.25,0.5,0}},
303       Gamma[4][4] = {{g,0,0,0},
304                      {1.,g,0,0},
305                      {-0.25,-0.25,g,0},
306                      {1./12,1./12,-2./3,g}},
307       b[4] = {5./6,-1./6,-1./6,0.5},
308       b2[4] = {0.75,-0.25,0.5,0};
309     ierr = TSRosWRegister(TSROSWRODAS3,3,4,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
310   }
311   {
312     const PetscReal g = 0.43586652150845899941601945119356;
313     const PetscReal
314       A[3][3] = {{0,0,0},
315                  {g,0,0},
316                  {g,0,0}},
317       Gamma[3][3] = {{g,0,0},
318                      {-0.19294655696029095575009695436041,g,0},
319                      {0,1.74927148125794685173529749738960,g}},
320       b[3] = {-0.75457412385404315829818998646589,1.94100407061964420292840123379419,-0.18642994676560104463021124732829},
321       b2[3] = {-1.53358745784149585370766523913002,2.81745131148625772213931745457622,-0.28386385364476186843165221544619};
322     ierr = TSRosWRegister(TSROSWSANDU3,3,3,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
323   }
324   {
325     const PetscReal s3 = PetscSqrtReal(3.),g = (3.0+s3)/6.0;
326     const PetscReal
327       A[3][3] = {{0,0,0},
328                  {1,0,0},
329                  {0.25,0.25,0}},
330       Gamma[3][3] = {{0,0,0},
331                      {(-3.0-s3)/6.0,g,0},
332                      {(-3.0-s3)/24.0,(-3.0-s3)/8.0,g}},
333         b[3] = {1./6.,1./6.,2./3.},
334           b2[3] = {1./4.,1./4.,1./2.};
335     ierr = TSRosWRegister(TSROSWASSP3P3S1C,3,3,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
336   }
337 
338   {
339     const PetscReal
340       A[4][4] = {{0,0,0,0},
341                  {1./2.,0,0,0},
342                  {1./2.,1./2.,0,0},
343                  {1./6.,1./6.,1./6.,0}},
344       Gamma[4][4] = {{1./2.,0,0,0},
345                      {0.0,1./4.,0,0},
346                      {-2.,-2./3.,2./3.,0},
347                      {1./2.,5./36.,-2./9,0}},
348         b[4] = {1./6.,1./6.,1./6.,1./2.},
349         b2[4] = {1./8.,3./4.,1./8.,0};
350      ierr = TSRosWRegister(TSROSWLASSP3P4S2C,3,4,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
351   }
352 
353   {
354     const PetscReal
355       A[4][4] = {{0,0,0,0},
356                  {1./2.,0,0,0},
357                  {1./2.,1./2.,0,0},
358                  {1./6.,1./6.,1./6.,0}},
359       Gamma[4][4] = {{1./2.,0,0,0},
360                      {0.0,3./4.,0,0},
361                      {-2./3.,-23./9.,2./9.,0},
362                      {1./18.,65./108.,-2./27,0}},
363         b[4] = {1./6.,1./6.,1./6.,1./2.},
364         b2[4] = {3./16.,10./16.,3./16.,0};
365      ierr = TSRosWRegister(TSROSWLLSSP3P4S2C,3,4,&A[0][0],&Gamma[0][0],b,b2,0,PETSC_NULL);CHKERRQ(ierr);
366   }
367 
368  {
369    PetscReal A[4][4],Gamma[4][4],b[4],b2[4];
370 
371    Gamma[0][0]=0.4358665215084589994160194475295062513822671686978816;
372    Gamma[0][1]=0; Gamma[0][2]=0; Gamma[0][3]=0;
373    Gamma[1][0]=-1.997527830934941248426324674704153457289527280554476;
374    Gamma[1][1]=0.4358665215084589994160194475295062513822671686978816;
375    Gamma[1][2]=0; Gamma[1][3]=0;
376    Gamma[2][0]=-1.007948511795029620852002345345404191008352770119903;
377    Gamma[2][1]=-0.004648958462629345562774289390054679806993396798458131;
378    Gamma[2][2]=0.4358665215084589994160194475295062513822671686978816;
379    Gamma[2][3]=0;
380    Gamma[3][0]=-0.6685429734233467180451604600279552604364311322650783;
381    Gamma[3][1]=0.6056625986449338476089525334450053439525178740492984;
382    Gamma[3][2]=-0.9717899277217721234705114616271378792182450260943198;
383    Gamma[3][3]=0;
384 
385    A[0][0]=0; A[0][1]=0; A[0][2]=0; A[0][3]=0;
386    A[1][0]=0.8717330430169179988320388950590125027645343373957631;
387    A[1][1]=0; A[1][2]=0; A[1][3]=0;
388    A[2][0]=0.5275890119763004115618079766722914408876108660811028;
389    A[2][1]=0.07241098802369958843819203208518599088698057726988732;
390    A[2][2]=0; A[2][3]=0;
391    A[3][0]=0.3990960076760701320627260685975778145384666450351314;
392    A[3][1]=-0.4375576546135194437228463747348862825846903771419953;
393    A[3][2]=1.038461646937449311660120300601880176655352737312713;
394    A[3][3]=0;
395 
396    b[0]=0.1876410243467238251612921333138006734899663569186926;
397    b[1]=-0.5952974735769549480478230473706443582188442040780541;
398    b[2]=0.9717899277217721234705114616271378792182450260943198;
399    b[3]=0.4358665215084589994160194475295062513822671686978816;
400 
401    b2[0]=0.2147402862233891404862383521089097657790734483804460;
402    b2[1]=-0.4851622638849390928209050538171743017757490232519684;
403    b2[2]=0.8687250025203875511662123688667549217531982787600080;
404    b2[3]=0.4016969751411624011684543450940068201770721128357014;
405 
406    PetscReal binterpt[4][3]={{2.2565812720167954547104627844105,-3.0826699111559187902922463354557,1.0137296634858471607430756831148},{1.349166413351089573796243820819,-2.4689115685996042534544925650515,0.52444768167155973161042570784064},{-2.4695174540533503758652847586647,5.7428279814696677152129332773553,-2.3015205996945452158771370439586},{-0.13623023131453465264142184656474,-0.19124650171414467146619437684812,0.76334325453713832352363565300308}};
407 
408    ierr = TSRosWRegister(TSROSWARK3,3,4,&A[0][0],&Gamma[0][0],b,b2,3,&binterpt[0][0]);CHKERRQ(ierr);
409   }
410 
411   PetscFunctionReturn(0);
412 }
413 
414 #undef __FUNCT__
415 #define __FUNCT__ "TSRosWRegisterDestroy"
416 /*@C
417    TSRosWRegisterDestroy - Frees the list of schemes that were registered by TSRosWRegister().
418 
419    Not Collective
420 
421    Level: advanced
422 
423 .keywords: TSRosW, register, destroy
424 .seealso: TSRosWRegister(), TSRosWRegisterAll(), TSRosWRegisterDynamic()
425 @*/
426 PetscErrorCode TSRosWRegisterDestroy(void)
427 {
428   PetscErrorCode ierr;
429   RosWTableauLink link;
430 
431   PetscFunctionBegin;
432   while ((link = RosWTableauList)) {
433     RosWTableau t = &link->tab;
434     RosWTableauList = link->next;
435     ierr = PetscFree5(t->A,t->Gamma,t->b,t->ASum,t->GammaSum);CHKERRQ(ierr);
436     ierr = PetscFree5(t->At,t->bt,t->GammaInv,t->GammaZeroDiag,t->GammaExplicitCorr);CHKERRQ(ierr);
437     ierr = PetscFree2(t->bembed,t->bembedt);CHKERRQ(ierr);
438     ierr = PetscFree(t->binterpt);CHKERRQ(ierr);
439     ierr = PetscFree(t->name);CHKERRQ(ierr);
440     ierr = PetscFree(link);CHKERRQ(ierr);
441   }
442   TSRosWRegisterAllCalled = PETSC_FALSE;
443   PetscFunctionReturn(0);
444 }
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "TSRosWInitializePackage"
448 /*@C
449   TSRosWInitializePackage - This function initializes everything in the TSRosW package. It is called
450   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to TSCreate_RosW()
451   when using static libraries.
452 
453   Input Parameter:
454   path - The dynamic library path, or PETSC_NULL
455 
456   Level: developer
457 
458 .keywords: TS, TSRosW, initialize, package
459 .seealso: PetscInitialize()
460 @*/
461 PetscErrorCode TSRosWInitializePackage(const char path[])
462 {
463   PetscErrorCode ierr;
464 
465   PetscFunctionBegin;
466   if (TSRosWPackageInitialized) PetscFunctionReturn(0);
467   TSRosWPackageInitialized = PETSC_TRUE;
468   ierr = TSRosWRegisterAll();CHKERRQ(ierr);
469   ierr = PetscRegisterFinalize(TSRosWFinalizePackage);CHKERRQ(ierr);
470   PetscFunctionReturn(0);
471 }
472 
473 #undef __FUNCT__
474 #define __FUNCT__ "TSRosWFinalizePackage"
475 /*@C
476   TSRosWFinalizePackage - This function destroys everything in the TSRosW package. It is
477   called from PetscFinalize().
478 
479   Level: developer
480 
481 .keywords: Petsc, destroy, package
482 .seealso: PetscFinalize()
483 @*/
484 PetscErrorCode TSRosWFinalizePackage(void)
485 {
486   PetscErrorCode ierr;
487 
488   PetscFunctionBegin;
489   TSRosWPackageInitialized = PETSC_FALSE;
490   ierr = TSRosWRegisterDestroy();CHKERRQ(ierr);
491   PetscFunctionReturn(0);
492 }
493 
494 #undef __FUNCT__
495 #define __FUNCT__ "TSRosWRegister"
496 /*@C
497    TSRosWRegister - register a Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation
498 
499    Not Collective, but the same schemes should be registered on all processes on which they will be used
500 
501    Input Parameters:
502 +  name - identifier for method
503 .  order - approximation order of method
504 .  s - number of stages, this is the dimension of the matrices below
505 .  A - Table of propagated stage coefficients (dimension s*s, row-major), strictly lower triangular
506 .  Gamma - Table of coefficients in implicit stage equations (dimension s*s, row-major), lower triangular with nonzero diagonal
507 .  b - Step completion table (dimension s)
508 -  bembed - Step completion table for a scheme of order one less (dimension s, PETSC_NULL if no embedded scheme is available)
509 .  pinterp - Order of the interpolation scheme, equal to the number of columns of binterpt
510 .  binterpt - Coefficients of the interpolation formula (dimension s*pinterp)
511 
512    Notes:
513    Several Rosenbrock W methods are provided, this function is only needed to create new methods.
514 
515    Level: advanced
516 
517 .keywords: TS, register
518 
519 .seealso: TSRosW
520 @*/
521 PetscErrorCode TSRosWRegister(const TSRosWType name,PetscInt order,PetscInt s,
522                               const PetscReal A[],const PetscReal Gamma[],const PetscReal b[],const PetscReal bembed[],
523                                  PetscInt pinterp,const PetscReal binterpt[])
524 {
525   PetscErrorCode ierr;
526   RosWTableauLink link;
527   RosWTableau t;
528   PetscInt i,j,k;
529   PetscScalar *GammaInv;
530 
531   PetscFunctionBegin;
532   PetscValidCharPointer(name,1);
533   PetscValidPointer(A,4);
534   PetscValidPointer(Gamma,5);
535   PetscValidPointer(b,6);
536   if (bembed) PetscValidPointer(bembed,7);
537 
538   ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr);
539   ierr = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr);
540   t = &link->tab;
541   ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
542   t->order = order;
543   t->s = s;
544   ierr = PetscMalloc5(s*s,PetscReal,&t->A,s*s,PetscReal,&t->Gamma,s,PetscReal,&t->b,s,PetscReal,&t->ASum,s,PetscReal,&t->GammaSum);CHKERRQ(ierr);
545   ierr = PetscMalloc5(s*s,PetscReal,&t->At,s,PetscReal,&t->bt,s*s,PetscReal,&t->GammaInv,s,PetscBool,&t->GammaZeroDiag,s*s,PetscReal,&t->GammaExplicitCorr);CHKERRQ(ierr);
546   ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr);
547   ierr = PetscMemcpy(t->Gamma,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr);
548   ierr = PetscMemcpy(t->GammaExplicitCorr,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr);
549   ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr);
550   if (bembed) {
551     ierr = PetscMalloc2(s,PetscReal,&t->bembed,s,PetscReal,&t->bembedt);CHKERRQ(ierr);
552     ierr = PetscMemcpy(t->bembed,bembed,s*sizeof(bembed[0]));CHKERRQ(ierr);
553   }
554   for (i=0; i<s; i++) {
555     t->ASum[i] = 0;
556     t->GammaSum[i] = 0;
557     for (j=0; j<s; j++) {
558       t->ASum[i] += A[i*s+j];
559       t->GammaSum[i] += Gamma[i*s+j];
560     }
561   }
562   ierr = PetscMalloc(s*s*sizeof(PetscScalar),&GammaInv);CHKERRQ(ierr); /* Need to use Scalar for inverse, then convert back to Real */
563   for (i=0; i<s*s; i++) GammaInv[i] = Gamma[i];
564   for (i=0; i<s; i++) {
565     if (Gamma[i*s+i] == 0.0) {
566       GammaInv[i*s+i] = 1.0;
567       t->GammaZeroDiag[i] = PETSC_TRUE;
568     } else {
569       t->GammaZeroDiag[i] = PETSC_FALSE;
570     }
571   }
572 
573   switch (s) {
574   case 1: GammaInv[0] = 1./GammaInv[0]; break;
575   case 2: ierr = Kernel_A_gets_inverse_A_2(GammaInv,0);CHKERRQ(ierr); break;
576   case 3: ierr = Kernel_A_gets_inverse_A_3(GammaInv,0);CHKERRQ(ierr); break;
577   case 4: ierr = Kernel_A_gets_inverse_A_4(GammaInv,0);CHKERRQ(ierr); break;
578   case 5: {
579     PetscInt ipvt5[5];
580     MatScalar work5[5*5];
581     ierr = Kernel_A_gets_inverse_A_5(GammaInv,ipvt5,work5,0);CHKERRQ(ierr); break;
582   }
583   case 6: ierr = Kernel_A_gets_inverse_A_6(GammaInv,0);CHKERRQ(ierr); break;
584   case 7: ierr = Kernel_A_gets_inverse_A_7(GammaInv,0);CHKERRQ(ierr); break;
585   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for %D stages",s);
586   }
587   for (i=0; i<s*s; i++) t->GammaInv[i] = PetscRealPart(GammaInv[i]);
588   ierr = PetscFree(GammaInv);CHKERRQ(ierr);
589 
590   for (i=0; i<s; i++) {
591     for (k=0; k<i+1; k++) {
592       t->GammaExplicitCorr[i*s+k]=(t->GammaExplicitCorr[i*s+k])*(t->GammaInv[k*s+k]);
593       for (j=k+1; j<i+1; j++) {
594         t->GammaExplicitCorr[i*s+k]+=(t->GammaExplicitCorr[i*s+j])*(t->GammaInv[j*s+k]);
595       }
596     }
597   }
598 
599   for (i=0; i<s; i++) {
600     for (j=0; j<s; j++) {
601       t->At[i*s+j] = 0;
602       for (k=0; k<s; k++) {
603         t->At[i*s+j] += t->A[i*s+k] * t->GammaInv[k*s+j];
604       }
605     }
606     t->bt[i] = 0;
607     for (j=0; j<s; j++) {
608       t->bt[i] += t->b[j] * t->GammaInv[j*s+i];
609     }
610     if (bembed) {
611       t->bembedt[i] = 0;
612       for (j=0; j<s; j++) {
613         t->bembedt[i] += t->bembed[j] * t->GammaInv[j*s+i];
614       }
615     }
616   }
617   t->ccfl = 1.0;                /* Fix this */
618 
619   t->pinterp = pinterp;
620   ierr = PetscMalloc(s*pinterp,&t->binterpt);CHKERRQ(ierr);
621 
622   link->next = RosWTableauList;
623   RosWTableauList = link;
624   PetscFunctionReturn(0);
625 }
626 
627 #undef __FUNCT__
628 #define __FUNCT__ "TSEvaluateStep_RosW"
629 /*
630  The step completion formula is
631 
632  x1 = x0 + b^T Y
633 
634  where Y is the multi-vector of stages corrections. This function can be called before or after ts->vec_sol has been
635  updated. Suppose we have a completion formula b and an embedded formula be of different order. We can write
636 
637  x1e = x0 + be^T Y
638      = x1 - b^T Y + be^T Y
639      = x1 + (be - b)^T Y
640 
641  so we can evaluate the method of different order even after the step has been optimistically completed.
642 */
643 static PetscErrorCode TSEvaluateStep_RosW(TS ts,PetscInt order,Vec X,PetscBool *done)
644 {
645   TS_RosW        *ros = (TS_RosW*)ts->data;
646   RosWTableau    tab  = ros->tableau;
647   PetscScalar    *w = ros->work;
648   PetscInt       i;
649   PetscErrorCode ierr;
650 
651   PetscFunctionBegin;
652   if (order == tab->order) {
653     if (ros->status == TS_STEP_INCOMPLETE) { /* Use standard completion formula */
654       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
655       for (i=0; i<tab->s; i++) w[i] = tab->bt[i];
656       ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr);
657     } else {ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);}
658     if (done) *done = PETSC_TRUE;
659     PetscFunctionReturn(0);
660   } else if (order == tab->order-1) {
661     if (!tab->bembedt) goto unavailable;
662     if (ros->status == TS_STEP_INCOMPLETE) { /* Use embedded completion formula */
663       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
664       for (i=0; i<tab->s; i++) w[i] = tab->bembedt[i];
665       ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr);
666     } else {                    /* Use rollback-and-recomplete formula (bembedt - bt) */
667       for (i=0; i<tab->s; i++) w[i] = tab->bembedt[i] - tab->bt[i];
668       ierr = VecCopy(ts->vec_sol,X);CHKERRQ(ierr);
669       ierr = VecMAXPY(X,tab->s,w,ros->Y);CHKERRQ(ierr);
670     }
671     if (done) *done = PETSC_TRUE;
672     PetscFunctionReturn(0);
673   }
674   unavailable:
675   if (done) *done = PETSC_FALSE;
676   else SETERRQ3(((PetscObject)ts)->comm,PETSC_ERR_SUP,"Rosenbrock-W '%s' of order %D cannot evaluate step at order %D",tab->name,tab->order,order);
677   PetscFunctionReturn(0);
678 }
679 
680 #undef __FUNCT__
681 #define __FUNCT__ "TSStep_RosW"
682 static PetscErrorCode TSStep_RosW(TS ts)
683 {
684   TS_RosW         *ros = (TS_RosW*)ts->data;
685   RosWTableau     tab  = ros->tableau;
686   const PetscInt  s    = tab->s;
687   const PetscReal *At  = tab->At,*Gamma = tab->Gamma,*ASum = tab->ASum,*GammaInv = tab->GammaInv;
688   const PetscReal *GammaExplicitCorr = tab->GammaExplicitCorr;
689   const PetscBool *GammaZeroDiag = tab->GammaZeroDiag;
690   PetscScalar     *w   = ros->work;
691   Vec             *Y   = ros->Y,Ydot = ros->Ydot,Zdot = ros->Zdot,Zstage = ros->Zstage;
692   SNES            snes;
693   TSAdapt         adapt;
694   PetscInt        i,j,its,lits,reject,next_scheme;
695   PetscReal       next_time_step;
696   PetscBool       accept;
697   PetscErrorCode  ierr;
698   MatStructure    str;
699 
700   PetscFunctionBegin;
701   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
702   next_time_step = ts->time_step;
703   accept = PETSC_TRUE;
704   ros->status = TS_STEP_INCOMPLETE;
705 
706   for (reject=0; reject<ts->max_reject && !ts->reason; reject++,ts->reject++) {
707     const PetscReal h = ts->time_step;
708     for (i=0; i<s; i++) {
709       ros->stage_time = ts->ptime + h*ASum[i];
710       if (GammaZeroDiag[i]) {
711         ros->stage_explicit = PETSC_TRUE;
712         ros->shift = 1./h;
713       } else {
714         ros->stage_explicit = PETSC_FALSE;
715         ros->shift = 1./(h*Gamma[i*s+i]);
716       }
717 
718       ierr = VecCopy(ts->vec_sol,Zstage);CHKERRQ(ierr);
719       for (j=0; j<i; j++) w[j] = At[i*s+j];
720       ierr = VecMAXPY(Zstage,i,w,Y);CHKERRQ(ierr);
721 
722       for (j=0; j<i; j++) w[j] = 1./h * GammaInv[i*s+j];
723       ierr = VecZeroEntries(Zdot);CHKERRQ(ierr);
724       ierr = VecMAXPY(Zdot,i,w,Y);CHKERRQ(ierr);
725 
726       /* Initial guess taken from last stage */
727       ierr = VecZeroEntries(Y[i]);CHKERRQ(ierr);
728 
729       if (!ros->stage_explicit) {
730         if (!ros->recompute_jacobian && !i) {
731           ierr = SNESSetLagJacobian(snes,-2);CHKERRQ(ierr); /* Recompute the Jacobian on this solve, but not again */
732         }
733         ierr = SNESSolve(snes,PETSC_NULL,Y[i]);CHKERRQ(ierr);
734         ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr);
735         ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr);
736         ts->nonlinear_its += its; ts->linear_its += lits;
737         ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
738         ierr = TSAdaptCheckStage(adapt,ts,&accept);CHKERRQ(ierr);
739         if (!accept) goto reject_step;
740       } else {
741         Mat J,Jp;
742         ierr = VecZeroEntries(Ydot);CHKERRQ(ierr); /* Evaluate Y[i]=G(t,Ydot=0,Zstage) */
743         ierr = TSComputeIFunction(ts,ros->stage_time,Zstage,Ydot,Y[i],PETSC_FALSE);CHKERRQ(ierr);
744         ierr = VecScale(Y[i],-1.0);
745         ierr = VecAXPY(Y[i],-1.0,Zdot);CHKERRQ(ierr); /*Y[i]=F(Zstage)-Zdot[=GammaInv*Y]*/
746 
747         ierr = VecZeroEntries(Zstage);CHKERRQ(ierr); /* Zstage = GammaExplicitCorr[i,j] * Y[j] */
748         for (j=0; j<i; j++) w[j] = GammaExplicitCorr[i*s+j];
749         ierr = VecMAXPY(Zstage,i,w,Y);CHKERRQ(ierr);
750         /*Y[i] += Y[i] + Jac*Zstage[=Jac*GammaExplicitCorr[i,j] * Y[j]] */
751         str = SAME_NONZERO_PATTERN;
752         ierr = TSGetIJacobian(ts,&J,&Jp,PETSC_NULL,PETSC_NULL);
753         ierr = TSComputeIJacobian(ts,ros->stage_time,ts->vec_sol,Ydot,0,&J,&Jp,&str,PETSC_FALSE);CHKERRQ(ierr);
754         ierr = MatMult(J,Zstage,Zdot);
755 
756         ierr = VecAXPY(Y[i],-1.0,Zdot);CHKERRQ(ierr);
757         ierr = VecScale(Y[i],h);
758         ts->linear_its += 1;
759       }
760     }
761     ierr = TSEvaluateStep(ts,tab->order,ts->vec_sol,PETSC_NULL);CHKERRQ(ierr);
762     ros->status = TS_STEP_PENDING;
763 
764     /* Register only the current method as a candidate because we're not supporting multiple candidates yet. */
765     ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
766     ierr = TSAdaptCandidatesClear(adapt);CHKERRQ(ierr);
767     ierr = TSAdaptCandidateAdd(adapt,tab->name,tab->order,1,tab->ccfl,1.*tab->s,PETSC_TRUE);CHKERRQ(ierr);
768     ierr = TSAdaptChoose(adapt,ts,ts->time_step,&next_scheme,&next_time_step,&accept);CHKERRQ(ierr);
769     if (accept) {
770       /* ignore next_scheme for now */
771       ts->ptime += ts->time_step;
772       ts->time_step = next_time_step;
773       ts->steps++;
774       ros->status = TS_STEP_COMPLETE;
775       break;
776     } else {                    /* Roll back the current step */
777       for (i=0; i<s; i++) w[i] = -tab->bt[i];
778       ierr = VecMAXPY(ts->vec_sol,s,w,Y);CHKERRQ(ierr);
779       ts->time_step = next_time_step;
780       ros->status = TS_STEP_INCOMPLETE;
781     }
782     reject_step: continue;
783   }
784   if (ros->status != TS_STEP_COMPLETE && !ts->reason) ts->reason = TS_DIVERGED_STEP_REJECTED;
785   PetscFunctionReturn(0);
786 }
787 
788 #undef __FUNCT__
789 #define __FUNCT__ "TSInterpolate_RosW"
790 static PetscErrorCode TSInterpolate_RosW(TS ts,PetscReal itime,Vec X)
791 {
792   TS_RosW        *ros = (TS_RosW*)ts->data;
793   PetscInt s = ros->tableau->s,pinterp = ros->tableau->pinterp,i,j;
794   PetscReal h;
795   PetscReal tt,t;
796   PetscScalar *bt;
797   const PetscReal *Bt = ros->tableau->binterpt;
798   PetscErrorCode ierr;
799   const PetscReal *GammaInv = ros->tableau->GammaInv;
800   PetscScalar     *w   = ros->work;
801   Vec             *Y   = ros->Y;
802 
803   PetscFunctionBegin;
804   if (!Bt) SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_SUP,"TSRosW %s does not have an interpolation formula",ros->tableau->name);
805 
806   switch (ros->status) {
807   case TS_STEP_INCOMPLETE:
808   case TS_STEP_PENDING:
809     h = ts->time_step;
810     t = (itime - ts->ptime)/h;
811     break;
812   case TS_STEP_COMPLETE:
813     h = ts->time_step_prev;
814     t = (itime - ts->ptime)/h + 1; /* In the interval [0,1] */
815     break;
816   default: SETERRQ(((PetscObject)ts)->comm,PETSC_ERR_PLIB,"Invalid TSStepStatus");
817   }
818   ierr = PetscMalloc(s,&bt);CHKERRQ(ierr);
819   for (i=0; i<s; i++) bt[i] = 0;
820   for (j=0,tt=t; j<pinterp; j++,tt*=t) {
821     for (i=0; i<s; i++) {
822       bt[i] += h * Bt[i*pinterp+j] * tt;
823     }
824   }
825 
826   /* y(t+tt*h) = y(t) + Sum bt(tt) * GammaInv * Ydot */
827   /*X<-0*/
828   ierr = VecZeroEntries(X);CHKERRQ(ierr);
829 
830   /*X<- Sum bt_i * GammaInv(i,1:i) * Y(1:i) */
831   for (i=0; i<s; i++) {
832     for (j=0; j<=i; j++) w[j] =  bt[i]*GammaInv[i*s+j];
833     ierr = VecMAXPY(X,i,w,Y);CHKERRQ(ierr);
834   }
835 
836   /*X<-y(t) + X*/
837   ierr = VecAXPY(X,1.0,ts->vec_sol);CHKERRQ(ierr);
838 
839   ierr = PetscFree(bt);CHKERRQ(ierr);
840 
841   PetscFunctionReturn(0);
842 }
843 
844 /*------------------------------------------------------------*/
845 #undef __FUNCT__
846 #define __FUNCT__ "TSReset_RosW"
847 static PetscErrorCode TSReset_RosW(TS ts)
848 {
849   TS_RosW        *ros = (TS_RosW*)ts->data;
850   PetscInt       s;
851   PetscErrorCode ierr;
852 
853   PetscFunctionBegin;
854   if (!ros->tableau) PetscFunctionReturn(0);
855    s = ros->tableau->s;
856   ierr = VecDestroyVecs(s,&ros->Y);CHKERRQ(ierr);
857   ierr = VecDestroy(&ros->Ydot);CHKERRQ(ierr);
858   ierr = VecDestroy(&ros->Ystage);CHKERRQ(ierr);
859   ierr = VecDestroy(&ros->Zdot);CHKERRQ(ierr);
860   ierr = VecDestroy(&ros->Zstage);CHKERRQ(ierr);
861   ierr = PetscFree(ros->work);CHKERRQ(ierr);
862   PetscFunctionReturn(0);
863 }
864 
865 #undef __FUNCT__
866 #define __FUNCT__ "TSDestroy_RosW"
867 static PetscErrorCode TSDestroy_RosW(TS ts)
868 {
869   PetscErrorCode  ierr;
870 
871   PetscFunctionBegin;
872   ierr = TSReset_RosW(ts);CHKERRQ(ierr);
873   ierr = PetscFree(ts->data);CHKERRQ(ierr);
874   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","",PETSC_NULL);CHKERRQ(ierr);
875   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","",PETSC_NULL);CHKERRQ(ierr);
876   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","",PETSC_NULL);CHKERRQ(ierr);
877   PetscFunctionReturn(0);
878 }
879 
880 /*
881   This defines the nonlinear equation that is to be solved with SNES
882   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
883 */
884 #undef __FUNCT__
885 #define __FUNCT__ "SNESTSFormFunction_RosW"
886 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes,Vec X,Vec F,TS ts)
887 {
888   TS_RosW        *ros = (TS_RosW*)ts->data;
889   PetscErrorCode ierr;
890 
891   PetscFunctionBegin;
892   ierr = VecWAXPY(ros->Ydot,ros->shift,X,ros->Zdot);CHKERRQ(ierr); /* Ydot = shift*X + Zdot */
893   ierr = VecWAXPY(ros->Ystage,1.0,X,ros->Zstage);CHKERRQ(ierr);    /* Ystage = X + Zstage */
894   ierr = TSComputeIFunction(ts,ros->stage_time,ros->Ystage,ros->Ydot,F,PETSC_FALSE);CHKERRQ(ierr);
895   PetscFunctionReturn(0);
896 }
897 
898 #undef __FUNCT__
899 #define __FUNCT__ "SNESTSFormJacobian_RosW"
900 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *str,TS ts)
901 {
902   TS_RosW        *ros = (TS_RosW*)ts->data;
903   PetscErrorCode ierr;
904 
905   PetscFunctionBegin;
906   /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */
907   ierr = TSComputeIJacobian(ts,ros->stage_time,ros->Ystage,ros->Ydot,ros->shift,A,B,str,PETSC_TRUE);CHKERRQ(ierr);
908   PetscFunctionReturn(0);
909 }
910 
911 #undef __FUNCT__
912 #define __FUNCT__ "TSSetUp_RosW"
913 static PetscErrorCode TSSetUp_RosW(TS ts)
914 {
915   TS_RosW        *ros = (TS_RosW*)ts->data;
916   RosWTableau    tab  = ros->tableau;
917   PetscInt       s    = tab->s;
918   PetscErrorCode ierr;
919 
920   PetscFunctionBegin;
921   if (!ros->tableau) {
922     ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);
923   }
924   ierr = VecDuplicateVecs(ts->vec_sol,s,&ros->Y);CHKERRQ(ierr);
925   ierr = VecDuplicate(ts->vec_sol,&ros->Ydot);CHKERRQ(ierr);
926   ierr = VecDuplicate(ts->vec_sol,&ros->Ystage);CHKERRQ(ierr);
927   ierr = VecDuplicate(ts->vec_sol,&ros->Zdot);CHKERRQ(ierr);
928   ierr = VecDuplicate(ts->vec_sol,&ros->Zstage);CHKERRQ(ierr);
929   ierr = PetscMalloc(s*sizeof(ros->work[0]),&ros->work);CHKERRQ(ierr);
930   PetscFunctionReturn(0);
931 }
932 /*------------------------------------------------------------*/
933 
934 #undef __FUNCT__
935 #define __FUNCT__ "TSSetFromOptions_RosW"
936 static PetscErrorCode TSSetFromOptions_RosW(TS ts)
937 {
938   TS_RosW        *ros = (TS_RosW*)ts->data;
939   PetscErrorCode ierr;
940   char           rostype[256];
941 
942   PetscFunctionBegin;
943   ierr = PetscOptionsHead("RosW ODE solver options");CHKERRQ(ierr);
944   {
945     RosWTableauLink link;
946     PetscInt count,choice;
947     PetscBool flg;
948     const char **namelist;
949     SNES snes;
950 
951     ierr = PetscStrncpy(rostype,TSRosWDefault,sizeof rostype);CHKERRQ(ierr);
952     for (link=RosWTableauList,count=0; link; link=link->next,count++) ;
953     ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr);
954     for (link=RosWTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
955     ierr = PetscOptionsEList("-ts_rosw_type","Family of Rosenbrock-W method","TSRosWSetType",(const char*const*)namelist,count,rostype,&choice,&flg);CHKERRQ(ierr);
956     ierr = TSRosWSetType(ts,flg ? namelist[choice] : rostype);CHKERRQ(ierr);
957     ierr = PetscFree(namelist);CHKERRQ(ierr);
958 
959     ierr = PetscOptionsBool("-ts_rosw_recompute_jacobian","Recompute the Jacobian at each stage","TSRosWSetRecomputeJacobian",ros->recompute_jacobian,&ros->recompute_jacobian,PETSC_NULL);CHKERRQ(ierr);
960 
961     /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */
962     ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
963     if (!((PetscObject)snes)->type_name) {
964       ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);
965     }
966     ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
967   }
968   ierr = PetscOptionsTail();CHKERRQ(ierr);
969   PetscFunctionReturn(0);
970 }
971 
972 #undef __FUNCT__
973 #define __FUNCT__ "PetscFormatRealArray"
974 static PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
975 {
976   PetscErrorCode ierr;
977   PetscInt i;
978   size_t left,count;
979   char *p;
980 
981   PetscFunctionBegin;
982   for (i=0,p=buf,left=len; i<n; i++) {
983     ierr = PetscSNPrintfCount(p,left,fmt,&count,x[i]);CHKERRQ(ierr);
984     if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
985     left -= count;
986     p += count;
987     *p++ = ' ';
988   }
989   p[i ? 0 : -1] = 0;
990   PetscFunctionReturn(0);
991 }
992 
993 #undef __FUNCT__
994 #define __FUNCT__ "TSView_RosW"
995 static PetscErrorCode TSView_RosW(TS ts,PetscViewer viewer)
996 {
997   TS_RosW        *ros = (TS_RosW*)ts->data;
998   RosWTableau    tab  = ros->tableau;
999   PetscBool      iascii;
1000   PetscErrorCode ierr;
1001 
1002   PetscFunctionBegin;
1003   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1004   if (iascii) {
1005     const TSRosWType rostype;
1006     PetscInt i;
1007     PetscReal abscissa[512];
1008     char buf[512];
1009     ierr = TSRosWGetType(ts,&rostype);CHKERRQ(ierr);
1010     ierr = PetscViewerASCIIPrintf(viewer,"  Rosenbrock-W %s\n",rostype);CHKERRQ(ierr);
1011     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->ASum);CHKERRQ(ierr);
1012     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa of A       = %s\n",buf);CHKERRQ(ierr);
1013     for (i=0; i<tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i];
1014     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,abscissa);CHKERRQ(ierr);
1015     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa of A+Gamma = %s\n",buf);CHKERRQ(ierr);
1016   }
1017   ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr);
1018   PetscFunctionReturn(0);
1019 }
1020 
1021 #undef __FUNCT__
1022 #define __FUNCT__ "TSRosWSetType"
1023 /*@C
1024   TSRosWSetType - Set the type of Rosenbrock-W scheme
1025 
1026   Logically collective
1027 
1028   Input Parameter:
1029 +  ts - timestepping context
1030 -  rostype - type of Rosenbrock-W scheme
1031 
1032   Level: beginner
1033 
1034 .seealso: TSRosWGetType(), TSROSW, TSROSW2M, TSROSW2P, TSROSWRA3PW, TSROSWRA34PW2, TSROSWRODAS3, TSROSWSANDU3, TSROSWASSP3P3S1C, TSROSWLASSP3P4S2C, TSROSWLLSSP3P4S2C, TSROSWARK3
1035 @*/
1036 PetscErrorCode TSRosWSetType(TS ts,const TSRosWType rostype)
1037 {
1038   PetscErrorCode ierr;
1039 
1040   PetscFunctionBegin;
1041   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1042   ierr = PetscTryMethod(ts,"TSRosWSetType_C",(TS,const TSRosWType),(ts,rostype));CHKERRQ(ierr);
1043   PetscFunctionReturn(0);
1044 }
1045 
1046 #undef __FUNCT__
1047 #define __FUNCT__ "TSRosWGetType"
1048 /*@C
1049   TSRosWGetType - Get the type of Rosenbrock-W scheme
1050 
1051   Logically collective
1052 
1053   Input Parameter:
1054 .  ts - timestepping context
1055 
1056   Output Parameter:
1057 .  rostype - type of Rosenbrock-W scheme
1058 
1059   Level: intermediate
1060 
1061 .seealso: TSRosWGetType()
1062 @*/
1063 PetscErrorCode TSRosWGetType(TS ts,const TSRosWType *rostype)
1064 {
1065   PetscErrorCode ierr;
1066 
1067   PetscFunctionBegin;
1068   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1069   ierr = PetscUseMethod(ts,"TSRosWGetType_C",(TS,const TSRosWType*),(ts,rostype));CHKERRQ(ierr);
1070   PetscFunctionReturn(0);
1071 }
1072 
1073 #undef __FUNCT__
1074 #define __FUNCT__ "TSRosWSetRecomputeJacobian"
1075 /*@C
1076   TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step.
1077 
1078   Logically collective
1079 
1080   Input Parameter:
1081 +  ts - timestepping context
1082 -  flg - PETSC_TRUE to recompute the Jacobian at each stage
1083 
1084   Level: intermediate
1085 
1086 .seealso: TSRosWGetType()
1087 @*/
1088 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts,PetscBool flg)
1089 {
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1094   ierr = PetscTryMethod(ts,"TSRosWSetRecomputeJacobian_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 EXTERN_C_BEGIN
1099 #undef __FUNCT__
1100 #define __FUNCT__ "TSRosWGetType_RosW"
1101 PetscErrorCode  TSRosWGetType_RosW(TS ts,const TSRosWType *rostype)
1102 {
1103   TS_RosW        *ros = (TS_RosW*)ts->data;
1104   PetscErrorCode ierr;
1105 
1106   PetscFunctionBegin;
1107   if (!ros->tableau) {ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);}
1108   *rostype = ros->tableau->name;
1109   PetscFunctionReturn(0);
1110 }
1111 #undef __FUNCT__
1112 #define __FUNCT__ "TSRosWSetType_RosW"
1113 PetscErrorCode  TSRosWSetType_RosW(TS ts,const TSRosWType rostype)
1114 {
1115   TS_RosW         *ros = (TS_RosW*)ts->data;
1116   PetscErrorCode  ierr;
1117   PetscBool       match;
1118   RosWTableauLink link;
1119 
1120   PetscFunctionBegin;
1121   if (ros->tableau) {
1122     ierr = PetscStrcmp(ros->tableau->name,rostype,&match);CHKERRQ(ierr);
1123     if (match) PetscFunctionReturn(0);
1124   }
1125   for (link = RosWTableauList; link; link=link->next) {
1126     ierr = PetscStrcmp(link->tab.name,rostype,&match);CHKERRQ(ierr);
1127     if (match) {
1128       ierr = TSReset_RosW(ts);CHKERRQ(ierr);
1129       ros->tableau = &link->tab;
1130       PetscFunctionReturn(0);
1131     }
1132   }
1133   SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",rostype);
1134   PetscFunctionReturn(0);
1135 }
1136 
1137 #undef __FUNCT__
1138 #define __FUNCT__ "TSRosWSetRecomputeJacobian_RosW"
1139 PetscErrorCode  TSRosWSetRecomputeJacobian_RosW(TS ts,PetscBool flg)
1140 {
1141   TS_RosW *ros = (TS_RosW*)ts->data;
1142 
1143   PetscFunctionBegin;
1144   ros->recompute_jacobian = flg;
1145   PetscFunctionReturn(0);
1146 }
1147 EXTERN_C_END
1148 
1149 /* ------------------------------------------------------------ */
1150 /*MC
1151       TSROSW - ODE solver using Rosenbrock-W schemes
1152 
1153   These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly
1154   nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part
1155   of the equation using TSSetIFunction() and the non-stiff part with TSSetRHSFunction().
1156 
1157   Notes:
1158   This method currently only works with autonomous ODE and DAE.
1159 
1160   Developer notes:
1161   Rosenbrock-W methods are typically specified for autonomous ODE
1162 
1163 $  xdot = f(x)
1164 
1165   by the stage equations
1166 
1167 $  k_i = h f(x_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j
1168 
1169   and step completion formula
1170 
1171 $  x_1 = x_0 + sum_j b_j k_j
1172 
1173   with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(x)
1174   and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner,
1175   we define new variables for the stage equations
1176 
1177 $  y_i = gamma_ij k_j
1178 
1179   The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define
1180 
1181 $  A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-i}
1182 
1183   to rewrite the method as
1184 
1185 $  [M/(h gamma_ii) - J] y_i = f(x_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j
1186 $  x_1 = x_0 + sum_j bt_j y_j
1187 
1188    where we have introduced the mass matrix M. Continue by defining
1189 
1190 $  ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j
1191 
1192    or, more compactly in tensor notation
1193 
1194 $  Ydot = 1/h (Gamma^{-1} \otimes I) Y .
1195 
1196    Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current
1197    stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the
1198    equation
1199 
1200 $  g(x_0 + sum_j a_ij y_j + y_i, ydot_i) = 0
1201 
1202    with initial guess y_i = 0.
1203 
1204   Level: beginner
1205 
1206 .seealso:  TSCreate(), TS, TSSetType(), TSRosWSetType(), TSRosWRegister()
1207 
1208 M*/
1209 EXTERN_C_BEGIN
1210 #undef __FUNCT__
1211 #define __FUNCT__ "TSCreate_RosW"
1212 PetscErrorCode  TSCreate_RosW(TS ts)
1213 {
1214   TS_RosW        *ros;
1215   PetscErrorCode ierr;
1216 
1217   PetscFunctionBegin;
1218 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
1219   ierr = TSRosWInitializePackage(PETSC_NULL);CHKERRQ(ierr);
1220 #endif
1221 
1222   ts->ops->reset          = TSReset_RosW;
1223   ts->ops->destroy        = TSDestroy_RosW;
1224   ts->ops->view           = TSView_RosW;
1225   ts->ops->setup          = TSSetUp_RosW;
1226   ts->ops->step           = TSStep_RosW;
1227   ts->ops->interpolate    = TSInterpolate_RosW;
1228   ts->ops->evaluatestep   = TSEvaluateStep_RosW;
1229   ts->ops->setfromoptions = TSSetFromOptions_RosW;
1230   ts->ops->snesfunction   = SNESTSFormFunction_RosW;
1231   ts->ops->snesjacobian   = SNESTSFormJacobian_RosW;
1232 
1233   ierr = PetscNewLog(ts,TS_RosW,&ros);CHKERRQ(ierr);
1234   ts->data = (void*)ros;
1235 
1236   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","TSRosWGetType_RosW",TSRosWGetType_RosW);CHKERRQ(ierr);
1237   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","TSRosWSetType_RosW",TSRosWSetType_RosW);CHKERRQ(ierr);
1238   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","TSRosWSetRecomputeJacobian_RosW",TSRosWSetRecomputeJacobian_RosW);CHKERRQ(ierr);
1239   PetscFunctionReturn(0);
1240 }
1241 EXTERN_C_END
1242