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