xref: /petsc/src/ts/impls/rosw/rosw.c (revision e408995a0071fdf06114d394b0caf1044a1a91b4)
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 = TSROSW2P;
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   PetscReal *b;                 /* Step completion table */
30   PetscReal *ASum;              /* Row sum of A */
31   PetscReal *GammaSum;          /* Row sum of Gamma, only needed for non-autonomous systems */
32   PetscReal *At;                /* Propagation table in transformed variables */
33   PetscReal *bt;                /* Step completion table in transformed variables  */
34   PetscReal *GammaInv;          /* Inverse of Gamma, used for transformed variables */
35 };
36 typedef struct _RosWTableauLink *RosWTableauLink;
37 struct _RosWTableauLink {
38   struct _RosWTableau tab;
39   RosWTableauLink next;
40 };
41 static RosWTableauLink RosWTableauList;
42 
43 typedef struct {
44   RosWTableau tableau;
45   Vec         *Y;               /* States computed during the step, used to complete the step */
46   Vec         Ydot;             /* Work vector holding Ydot during residual evaluation */
47   Vec         Ystage;           /* Work vector for the state value at each stage */
48   Vec         Zdot;             /* Ydot = Zdot + shift*Y */
49   Vec         Zstage;           /* Y = Zstage + Y */
50   PetscScalar *work;            /* Scalar work */
51   PetscReal   shift;
52   PetscReal   stage_time;
53   PetscBool   recompute_jacobian; /* Recompute the Jacobian at each stage, default is to freeze the Jacobian at the start of each step */
54 } TS_RosW;
55 
56 #undef __FUNCT__
57 #define __FUNCT__ "TSRosWRegisterAll"
58 /*@C
59   TSRosWRegisterAll - Registers all of the additive Runge-Kutta implicit-explicit methods in TSRosW
60 
61   Not Collective, but should be called by all processes which will need the schemes to be registered
62 
63   Level: advanced
64 
65 .keywords: TS, TSRosW, register, all
66 
67 .seealso:  TSRosWRegisterDestroy()
68 @*/
69 PetscErrorCode TSRosWRegisterAll(void)
70 {
71   PetscErrorCode ierr;
72 
73   PetscFunctionBegin;
74   if (TSRosWRegisterAllCalled) PetscFunctionReturn(0);
75   TSRosWRegisterAllCalled = PETSC_TRUE;
76 
77   {
78     const PetscReal g = 1. + 1./PetscSqrtReal(2.0);
79     const PetscReal
80       A[2][2] = {{0,0}, {1.,0}},
81       Gamma[2][2] = {{g,0}, {-2.*g,g}},
82       b[2] = {0.5,0.5};
83     ierr = TSRosWRegister(TSROSW2P,2,2,&A[0][0],&Gamma[0][0],b);CHKERRQ(ierr);
84   }
85   {
86     const PetscReal g = 1. - 1./PetscSqrtReal(2.0);
87     const PetscReal
88       A[2][2] = {{0,0}, {1.,0}},
89       Gamma[2][2] = {{g,0}, {-2.*g,g}},
90       b[2] = {0.5,0.5};
91     ierr = TSRosWRegister(TSROSW2M,2,2,&A[0][0],&Gamma[0][0],b);CHKERRQ(ierr);
92   }
93   PetscFunctionReturn(0);
94 }
95 
96 #undef __FUNCT__
97 #define __FUNCT__ "TSRosWRegisterDestroy"
98 /*@C
99    TSRosWRegisterDestroy - Frees the list of schemes that were registered by TSRosWRegister().
100 
101    Not Collective
102 
103    Level: advanced
104 
105 .keywords: TSRosW, register, destroy
106 .seealso: TSRosWRegister(), TSRosWRegisterAll(), TSRosWRegisterDynamic()
107 @*/
108 PetscErrorCode TSRosWRegisterDestroy(void)
109 {
110   PetscErrorCode ierr;
111   RosWTableauLink link;
112 
113   PetscFunctionBegin;
114   while ((link = RosWTableauList)) {
115     RosWTableau t = &link->tab;
116     RosWTableauList = link->next;
117     ierr = PetscFree5(t->A,t->Gamma,t->b,t->ASum,t->GammaSum);CHKERRQ(ierr);
118     ierr = PetscFree3(t->At,t->bt,t->GammaInv);CHKERRQ(ierr);
119     ierr = PetscFree(t->name);CHKERRQ(ierr);
120     ierr = PetscFree(link);CHKERRQ(ierr);
121   }
122   TSRosWRegisterAllCalled = PETSC_FALSE;
123   PetscFunctionReturn(0);
124 }
125 
126 #undef __FUNCT__
127 #define __FUNCT__ "TSRosWInitializePackage"
128 /*@C
129   TSRosWInitializePackage - This function initializes everything in the TSRosW package. It is called
130   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to TSCreate_RosW()
131   when using static libraries.
132 
133   Input Parameter:
134   path - The dynamic library path, or PETSC_NULL
135 
136   Level: developer
137 
138 .keywords: TS, TSRosW, initialize, package
139 .seealso: PetscInitialize()
140 @*/
141 PetscErrorCode TSRosWInitializePackage(const char path[])
142 {
143   PetscErrorCode ierr;
144 
145   PetscFunctionBegin;
146   if (TSRosWPackageInitialized) PetscFunctionReturn(0);
147   TSRosWPackageInitialized = PETSC_TRUE;
148   ierr = TSRosWRegisterAll();CHKERRQ(ierr);
149   ierr = PetscRegisterFinalize(TSRosWFinalizePackage);CHKERRQ(ierr);
150   PetscFunctionReturn(0);
151 }
152 
153 #undef __FUNCT__
154 #define __FUNCT__ "TSRosWFinalizePackage"
155 /*@C
156   TSRosWFinalizePackage - This function destroys everything in the TSRosW package. It is
157   called from PetscFinalize().
158 
159   Level: developer
160 
161 .keywords: Petsc, destroy, package
162 .seealso: PetscFinalize()
163 @*/
164 PetscErrorCode TSRosWFinalizePackage(void)
165 {
166   PetscErrorCode ierr;
167 
168   PetscFunctionBegin;
169   TSRosWPackageInitialized = PETSC_FALSE;
170   ierr = TSRosWRegisterDestroy();CHKERRQ(ierr);
171   PetscFunctionReturn(0);
172 }
173 
174 #undef __FUNCT__
175 #define __FUNCT__ "TSRosWRegister"
176 /*@C
177    TSRosWRegister - register a Rosenbrock W scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation
178 
179    Not Collective, but the same schemes should be registered on all processes on which they will be used
180 
181    Input Parameters:
182 +  name - identifier for method
183 .  order - approximation order of method
184 .  s - number of stages, this is the dimension of the matrices below
185 .  A - Table of propagated stage coefficients (dimension s*s, row-major), strictly lower triangular
186 .  Gamma - Table of coefficients in implicit stage equations (dimension s*s, row-major), lower triangular with nonzero diagonal
187 -  b - Step completion table (dimension s)
188 
189    Notes:
190    Several Rosenbrock W methods are provided, this function is only needed to create new methods.
191 
192    Level: advanced
193 
194 .keywords: TS, register
195 
196 .seealso: TSRosW
197 @*/
198 PetscErrorCode TSRosWRegister(const TSRosWType name,PetscInt order,PetscInt s,
199                               const PetscReal A[],const PetscReal Gamma[],const PetscReal b[])
200 {
201   PetscErrorCode ierr;
202   RosWTableauLink link;
203   RosWTableau t;
204   PetscInt i,j,k;
205   PetscScalar *GammaInv;
206 
207   PetscFunctionBegin;
208   ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr);
209   ierr = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr);
210   t = &link->tab;
211   ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
212   t->order = order;
213   t->s = s;
214   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);
215   ierr = PetscMalloc3(s*s,PetscReal,&t->At,s,PetscReal,&t->bt,s*s,PetscReal,&t->GammaInv);CHKERRQ(ierr);
216   ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr);
217   ierr = PetscMemcpy(t->Gamma,Gamma,s*s*sizeof(Gamma[0]));CHKERRQ(ierr);
218   ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr);
219   for (i=0; i<s; i++) {
220     t->ASum[i] = 0;
221     t->GammaSum[i] = 0;
222     for (j=0; j<s; j++) {
223       t->ASum[i] += A[i*s+j];
224       t->GammaSum[i] = Gamma[i*s+j];
225     }
226   }
227   ierr = PetscMalloc(s*s*sizeof(PetscScalar),&GammaInv);CHKERRQ(ierr); /* Need to use Scalar for inverse, then convert back to Real */
228   for (i=0; i<s*s; i++) GammaInv[i] = Gamma[i];
229   switch (s) {
230   case 1: GammaInv[0] = 1./GammaInv[0]; break;
231   case 2: ierr = Kernel_A_gets_inverse_A_2(GammaInv,0);CHKERRQ(ierr); break;
232   case 3: ierr = Kernel_A_gets_inverse_A_3(GammaInv,0);CHKERRQ(ierr); break;
233   case 4: ierr = Kernel_A_gets_inverse_A_4(GammaInv,0);CHKERRQ(ierr); break;
234   case 5: {
235     PetscInt ipvt5[5];
236     MatScalar work5[5*5];
237     ierr = Kernel_A_gets_inverse_A_5(GammaInv,ipvt5,work5,0);CHKERRQ(ierr); break;
238   }
239   case 6: ierr = Kernel_A_gets_inverse_A_6(GammaInv,0);CHKERRQ(ierr); break;
240   case 7: ierr = Kernel_A_gets_inverse_A_7(GammaInv,0);CHKERRQ(ierr); break;
241   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for %D stages",s);
242   }
243   for (i=0; i<s*s; i++) t->GammaInv[i] = PetscRealPart(GammaInv[i]);
244   ierr = PetscFree(GammaInv);CHKERRQ(ierr);
245   for (i=0; i<s; i++) {
246     for (j=0; j<s; j++) {
247       t->At[i*s+j] = 0;
248       for (k=0; k<s; k++) {
249         t->At[i*s+j] += t->A[i*s+k] * t->GammaInv[k*s+j];
250       }
251     }
252     t->bt[i] = 0;
253     for (j=0; j<s; j++) {
254       t->bt[i] += t->b[j] * t->GammaInv[j*s+i];
255     }
256   }
257   link->next = RosWTableauList;
258   RosWTableauList = link;
259   PetscFunctionReturn(0);
260 }
261 
262 #undef __FUNCT__
263 #define __FUNCT__ "TSStep_RosW"
264 static PetscErrorCode TSStep_RosW(TS ts)
265 {
266   TS_RosW         *ros = (TS_RosW*)ts->data;
267   RosWTableau     tab  = ros->tableau;
268   const PetscInt  s    = tab->s;
269   const PetscReal *At  = tab->At,*Gamma = tab->Gamma,*bt = tab->bt,*ASum = tab->ASum,*GammaInv = tab->GammaInv;
270   PetscScalar     *w   = ros->work;
271   Vec             *Y   = ros->Y,Zdot = ros->Zdot,Zstage = ros->Zstage;
272   SNES            snes;
273   PetscInt        i,j,its,lits;
274   PetscReal       next_time_step;
275   PetscReal       h,t;
276   PetscErrorCode  ierr;
277 
278   PetscFunctionBegin;
279   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
280   next_time_step = ts->time_step;
281   h = ts->time_step;
282   t = ts->ptime;
283 
284   for (i=0; i<s; i++) {
285     ros->stage_time = t + h*ASum[i];
286     ros->shift = 1./(h*Gamma[i*s+i]);
287 
288     ierr = VecCopy(ts->vec_sol,Zstage);CHKERRQ(ierr);
289     ierr = VecMAXPY(Zstage,i,&At[i*s+0],Y);CHKERRQ(ierr);
290 
291     for (j=0; j<i; j++) w[j] = 1./h * GammaInv[i*s+j];
292     ierr = VecZeroEntries(Zdot);CHKERRQ(ierr);
293     ierr = VecMAXPY(Zdot,i,w,Y);CHKERRQ(ierr);
294 
295     /* Initial guess taken from last stage */
296     ierr = VecZeroEntries(Y[i]);CHKERRQ(ierr);
297 
298     if (!ros->recompute_jacobian && !i) {
299       ierr = SNESSetLagJacobian(snes,-2);CHKERRQ(ierr); /* Recompute the Jacobian on this solve, but not again */
300     }
301 
302     ierr = SNESSolve(snes,PETSC_NULL,Y[i]);CHKERRQ(ierr);
303     ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr);
304     ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr);
305     ts->nonlinear_its += its; ts->linear_its += lits;
306   }
307   ierr = VecMAXPY(ts->vec_sol,s,bt,Y);CHKERRQ(ierr);
308 
309   ts->ptime += ts->time_step;
310   ts->time_step = next_time_step;
311   ts->steps++;
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "TSInterpolate_RosW"
317 static PetscErrorCode TSInterpolate_RosW(TS ts,PetscReal itime,Vec X)
318 {
319   TS_RosW        *ros = (TS_RosW*)ts->data;
320 
321   PetscFunctionBegin;
322   SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_SUP,"TSRosW %s does not have an interpolation formula",ros->tableau->name);
323   PetscFunctionReturn(0);
324 }
325 
326 /*------------------------------------------------------------*/
327 #undef __FUNCT__
328 #define __FUNCT__ "TSReset_RosW"
329 static PetscErrorCode TSReset_RosW(TS ts)
330 {
331   TS_RosW        *ros = (TS_RosW*)ts->data;
332   PetscInt       s;
333   PetscErrorCode ierr;
334 
335   PetscFunctionBegin;
336   if (!ros->tableau) PetscFunctionReturn(0);
337    s = ros->tableau->s;
338   ierr = VecDestroyVecs(s,&ros->Y);CHKERRQ(ierr);
339   ierr = VecDestroy(&ros->Ydot);CHKERRQ(ierr);
340   ierr = VecDestroy(&ros->Ystage);CHKERRQ(ierr);
341   ierr = VecDestroy(&ros->Zdot);CHKERRQ(ierr);
342   ierr = VecDestroy(&ros->Zstage);CHKERRQ(ierr);
343   ierr = PetscFree(ros->work);CHKERRQ(ierr);
344   PetscFunctionReturn(0);
345 }
346 
347 #undef __FUNCT__
348 #define __FUNCT__ "TSDestroy_RosW"
349 static PetscErrorCode TSDestroy_RosW(TS ts)
350 {
351   PetscErrorCode  ierr;
352 
353   PetscFunctionBegin;
354   ierr = TSReset_RosW(ts);CHKERRQ(ierr);
355   ierr = PetscFree(ts->data);CHKERRQ(ierr);
356   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","",PETSC_NULL);CHKERRQ(ierr);
357   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","",PETSC_NULL);CHKERRQ(ierr);
358   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","",PETSC_NULL);CHKERRQ(ierr);
359   PetscFunctionReturn(0);
360 }
361 
362 /*
363   This defines the nonlinear equation that is to be solved with SNES
364   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
365 */
366 #undef __FUNCT__
367 #define __FUNCT__ "SNESTSFormFunction_RosW"
368 static PetscErrorCode SNESTSFormFunction_RosW(SNES snes,Vec X,Vec F,TS ts)
369 {
370   TS_RosW        *ros = (TS_RosW*)ts->data;
371   PetscErrorCode ierr;
372 
373   PetscFunctionBegin;
374   ierr = VecWAXPY(ros->Ydot,ros->shift,X,ros->Zdot);CHKERRQ(ierr); /* Ydot = shift*X + Zdot */
375   ierr = VecWAXPY(ros->Ystage,1.0,X,ros->Zstage);CHKERRQ(ierr);    /* Ystage = X + Zstage */
376   ierr = TSComputeIFunction(ts,ros->stage_time,ros->Ystage,ros->Ydot,F,PETSC_FALSE);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "SNESTSFormJacobian_RosW"
382 static PetscErrorCode SNESTSFormJacobian_RosW(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *str,TS ts)
383 {
384   TS_RosW        *ros = (TS_RosW*)ts->data;
385   PetscErrorCode ierr;
386 
387   PetscFunctionBegin;
388   /* ros->Ydot and ros->Ystage have already been computed in SNESTSFormFunction_RosW (SNES guarantees this) */
389   ierr = TSComputeIJacobian(ts,ros->stage_time,ros->Ystage,ros->Ydot,ros->shift,A,B,str,PETSC_TRUE);CHKERRQ(ierr);
390   PetscFunctionReturn(0);
391 }
392 
393 #undef __FUNCT__
394 #define __FUNCT__ "TSSetUp_RosW"
395 static PetscErrorCode TSSetUp_RosW(TS ts)
396 {
397   TS_RosW        *ros = (TS_RosW*)ts->data;
398   RosWTableau    tab  = ros->tableau;
399   PetscInt       s    = tab->s;
400   PetscErrorCode ierr;
401 
402   PetscFunctionBegin;
403   if (!ros->tableau) {
404     ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);
405   }
406   ierr = VecDuplicateVecs(ts->vec_sol,s,&ros->Y);CHKERRQ(ierr);
407   ierr = VecDuplicate(ts->vec_sol,&ros->Ydot);CHKERRQ(ierr);
408   ierr = VecDuplicate(ts->vec_sol,&ros->Ystage);CHKERRQ(ierr);
409   ierr = VecDuplicate(ts->vec_sol,&ros->Zdot);CHKERRQ(ierr);
410   ierr = VecDuplicate(ts->vec_sol,&ros->Zstage);CHKERRQ(ierr);
411   ierr = PetscMalloc(s*sizeof(ros->work[0]),&ros->work);CHKERRQ(ierr);
412   PetscFunctionReturn(0);
413 }
414 /*------------------------------------------------------------*/
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "TSSetFromOptions_RosW"
418 static PetscErrorCode TSSetFromOptions_RosW(TS ts)
419 {
420   TS_RosW        *ros = (TS_RosW*)ts->data;
421   PetscErrorCode ierr;
422   char           rostype[256];
423 
424   PetscFunctionBegin;
425   ierr = PetscOptionsHead("RosW ODE solver options");CHKERRQ(ierr);
426   {
427     RosWTableauLink link;
428     PetscInt count,choice;
429     PetscBool flg;
430     const char **namelist;
431     SNES snes;
432 
433     ierr = PetscStrncpy(rostype,TSRosWDefault,sizeof rostype);CHKERRQ(ierr);
434     for (link=RosWTableauList,count=0; link; link=link->next,count++) ;
435     ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr);
436     for (link=RosWTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
437     ierr = PetscOptionsEList("-ts_rosw_type","Family of Rosenbrock-W method","TSRosWSetType",(const char*const*)namelist,count,rostype,&choice,&flg);CHKERRQ(ierr);
438     ierr = TSRosWSetType(ts,flg ? namelist[choice] : rostype);CHKERRQ(ierr);
439     ierr = PetscFree(namelist);CHKERRQ(ierr);
440 
441     ierr = PetscOptionsBool("-ts_rosw_recompute_jacobian","Recompute the Jacobian at each stage","TSRosWSetRecomputeJacobian",ros->recompute_jacobian,&ros->recompute_jacobian,PETSC_NULL);CHKERRQ(ierr);
442 
443     /* Rosenbrock methods are linearly implicit, so set that unless the user has specifically asked for something else */
444     ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
445     if (!((PetscObject)snes)->type_name) {
446       ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);
447     }
448     ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
449   }
450   ierr = PetscOptionsTail();CHKERRQ(ierr);
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "PetscFormatRealArray"
456 static PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
457 {
458   PetscErrorCode ierr;
459   PetscInt i;
460   size_t left,count;
461   char *p;
462 
463   PetscFunctionBegin;
464   for (i=0,p=buf,left=len; i<n; i++) {
465     ierr = PetscSNPrintfCount(p,left,fmt,&count,x[i]);CHKERRQ(ierr);
466     if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
467     left -= count;
468     p += count;
469     *p++ = ' ';
470   }
471   p[i ? 0 : -1] = 0;
472   PetscFunctionReturn(0);
473 }
474 
475 #undef __FUNCT__
476 #define __FUNCT__ "TSView_RosW"
477 static PetscErrorCode TSView_RosW(TS ts,PetscViewer viewer)
478 {
479   TS_RosW        *ros = (TS_RosW*)ts->data;
480   RosWTableau    tab  = ros->tableau;
481   PetscBool      iascii;
482   PetscErrorCode ierr;
483 
484   PetscFunctionBegin;
485   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
486   if (iascii) {
487     const TSRosWType rostype;
488     PetscInt i;
489     PetscReal abscissa[512];
490     char buf[512];
491     ierr = TSRosWGetType(ts,&rostype);CHKERRQ(ierr);
492     ierr = PetscViewerASCIIPrintf(viewer,"  Rosenbrock-W %s\n",rostype);CHKERRQ(ierr);
493     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->ASum);CHKERRQ(ierr);
494     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa of A       = %s\n",buf);CHKERRQ(ierr);
495     for (i=0; i<tab->s; i++) abscissa[i] = tab->ASum[i] + tab->Gamma[i];
496     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,abscissa);CHKERRQ(ierr);
497     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa of A+Gamma = %s\n",buf);CHKERRQ(ierr);
498   }
499   ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr);
500   PetscFunctionReturn(0);
501 }
502 
503 #undef __FUNCT__
504 #define __FUNCT__ "TSRosWSetType"
505 /*@C
506   TSRosWSetType - Set the type of Rosenbrock-W scheme
507 
508   Logically collective
509 
510   Input Parameter:
511 +  ts - timestepping context
512 -  rostype - type of Rosenbrock-W scheme
513 
514   Level: intermediate
515 
516 .seealso: TSRosWGetType()
517 @*/
518 PetscErrorCode TSRosWSetType(TS ts,const TSRosWType rostype)
519 {
520   PetscErrorCode ierr;
521 
522   PetscFunctionBegin;
523   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
524   ierr = PetscTryMethod(ts,"TSRosWSetType_C",(TS,const TSRosWType),(ts,rostype));CHKERRQ(ierr);
525   PetscFunctionReturn(0);
526 }
527 
528 #undef __FUNCT__
529 #define __FUNCT__ "TSRosWGetType"
530 /*@C
531   TSRosWGetType - Get the type of Rosenbrock-W scheme
532 
533   Logically collective
534 
535   Input Parameter:
536 .  ts - timestepping context
537 
538   Output Parameter:
539 .  rostype - type of Rosenbrock-W scheme
540 
541   Level: intermediate
542 
543 .seealso: TSRosWGetType()
544 @*/
545 PetscErrorCode TSRosWGetType(TS ts,const TSRosWType *rostype)
546 {
547   PetscErrorCode ierr;
548 
549   PetscFunctionBegin;
550   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
551   ierr = PetscUseMethod(ts,"TSRosWGetType_C",(TS,const TSRosWType*),(ts,rostype));CHKERRQ(ierr);
552   PetscFunctionReturn(0);
553 }
554 
555 #undef __FUNCT__
556 #define __FUNCT__ "TSRosWSetRecomputeJacobian"
557 /*@C
558   TSRosWSetRecomputeJacobian - Set whether to recompute the Jacobian at each stage. The default is to update the Jacobian once per step.
559 
560   Logically collective
561 
562   Input Parameter:
563 +  ts - timestepping context
564 -  flg - PETSC_TRUE to recompute the Jacobian at each stage
565 
566   Level: intermediate
567 
568 .seealso: TSRosWGetType()
569 @*/
570 PetscErrorCode TSRosWSetRecomputeJacobian(TS ts,PetscBool flg)
571 {
572   PetscErrorCode ierr;
573 
574   PetscFunctionBegin;
575   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
576   ierr = PetscTryMethod(ts,"TSRosWSetRecomputeJacobian_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr);
577   PetscFunctionReturn(0);
578 }
579 
580 EXTERN_C_BEGIN
581 #undef __FUNCT__
582 #define __FUNCT__ "TSRosWGetType_RosW"
583 PetscErrorCode  TSRosWGetType_RosW(TS ts,const TSRosWType *rostype)
584 {
585   TS_RosW        *ros = (TS_RosW*)ts->data;
586   PetscErrorCode ierr;
587 
588   PetscFunctionBegin;
589   if (!ros->tableau) {ierr = TSRosWSetType(ts,TSRosWDefault);CHKERRQ(ierr);}
590   *rostype = ros->tableau->name;
591   PetscFunctionReturn(0);
592 }
593 #undef __FUNCT__
594 #define __FUNCT__ "TSRosWSetType_RosW"
595 PetscErrorCode  TSRosWSetType_RosW(TS ts,const TSRosWType rostype)
596 {
597   TS_RosW         *ros = (TS_RosW*)ts->data;
598   PetscErrorCode  ierr;
599   PetscBool       match;
600   RosWTableauLink link;
601 
602   PetscFunctionBegin;
603   if (ros->tableau) {
604     ierr = PetscStrcmp(ros->tableau->name,rostype,&match);CHKERRQ(ierr);
605     if (match) PetscFunctionReturn(0);
606   }
607   for (link = RosWTableauList; link; link=link->next) {
608     ierr = PetscStrcmp(link->tab.name,rostype,&match);CHKERRQ(ierr);
609     if (match) {
610       ierr = TSReset_RosW(ts);CHKERRQ(ierr);
611       ros->tableau = &link->tab;
612       PetscFunctionReturn(0);
613     }
614   }
615   SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",rostype);
616   PetscFunctionReturn(0);
617 }
618 
619 #undef __FUNCT__
620 #define __FUNCT__ "TSRosWSetRecomputeJacobian_RosW"
621 PetscErrorCode  TSRosWSetRecomputeJacobian_RosW(TS ts,PetscBool flg)
622 {
623   TS_RosW *ros = (TS_RosW*)ts->data;
624 
625   PetscFunctionBegin;
626   ros->recompute_jacobian = flg;
627   PetscFunctionReturn(0);
628 }
629 EXTERN_C_END
630 
631 /* ------------------------------------------------------------ */
632 /*MC
633       TSRosW - ODE solver using Rosenbrock-W schemes
634 
635   These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly
636   nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part
637   of the equation using TSSetIFunction() and the non-stiff part with TSSetRHSFunction().
638 
639   Notes:
640   This method currently only works with autonomous ODE and DAE.
641 
642   Developer notes:
643   Rosenbrock-W methods are typically specified for autonomous ODE
644 
645 $  xdot = f(x)
646 
647   by the stage equations
648 
649 $  k_i = h f(x_0 + sum_j alpha_ij k_j) + h J sum_j gamma_ij k_j
650 
651   and step completion formula
652 
653 $  x_1 = x_0 + sum_j b_j k_j
654 
655   with step size h and coefficients alpha_ij, gamma_ij, and b_i. Implementing the method in this form would require f(x)
656   and the Jacobian J to be available, in addition to the shifted matrix I - h gamma_ii J. Following Hairer and Wanner,
657   we define new variables for the stage equations
658 
659 $  y_i = gamma_ij k_j
660 
661   The k_j can be recovered because Gamma is invertible. Let C be the lower triangular part of Gamma^{-1} and define
662 
663 $  A = Alpha Gamma^{-1}, bt^T = b^T Gamma^{-i}
664 
665   to rewrite the method as
666 
667 $  [M/(h gamma_ii) - J] y_i = f(x_0 + sum_j a_ij y_j) + M sum_j (c_ij/h) y_j
668 $  x_1 = x_0 + sum_j bt_j y_j
669 
670    where we have introduced the mass matrix M. Continue by defining
671 
672 $  ydot_i = 1/(h gamma_ii) y_i - sum_j (c_ij/h) y_j
673 
674    or, more compactly in tensor notation
675 
676 $  Ydot = 1/h (Gamma^{-1} \otimes I) Y .
677 
678    Note that Gamma^{-1} is lower triangular. With this definition of Ydot in terms of known quantities and the current
679    stage y_i, the stage equations reduce to performing one Newton step (typically with a lagged Jacobian) on the
680    equation
681 
682 $  g(x_0 + sum_j a_ij y_j + y_i, ydot_i) = 0
683 
684    with initial guess y_i = 0.
685 
686   Level: beginner
687 
688 .seealso:  TSCreate(), TS, TSSetType(), TSRosWRegister()
689 
690 M*/
691 EXTERN_C_BEGIN
692 #undef __FUNCT__
693 #define __FUNCT__ "TSCreate_RosW"
694 PetscErrorCode  TSCreate_RosW(TS ts)
695 {
696   TS_RosW        *ros;
697   PetscErrorCode ierr;
698 
699   PetscFunctionBegin;
700 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
701   ierr = TSRosWInitializePackage(PETSC_NULL);CHKERRQ(ierr);
702 #endif
703 
704   ts->ops->reset          = TSReset_RosW;
705   ts->ops->destroy        = TSDestroy_RosW;
706   ts->ops->view           = TSView_RosW;
707   ts->ops->setup          = TSSetUp_RosW;
708   ts->ops->step           = TSStep_RosW;
709   ts->ops->interpolate    = TSInterpolate_RosW;
710   ts->ops->setfromoptions = TSSetFromOptions_RosW;
711   ts->ops->snesfunction   = SNESTSFormFunction_RosW;
712   ts->ops->snesjacobian   = SNESTSFormJacobian_RosW;
713 
714   ierr = PetscNewLog(ts,TS_RosW,&ros);CHKERRQ(ierr);
715   ts->data = (void*)ros;
716 
717   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWGetType_C","TSRosWGetType_RosW",TSRosWGetType_RosW);CHKERRQ(ierr);
718   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetType_C","TSRosWSetType_RosW",TSRosWSetType_RosW);CHKERRQ(ierr);
719   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSRosWSetRecomputeJacobian_C","TSRosWSetRecomputeJacobian_RosW",TSRosWSetRecomputeJacobian_RosW);CHKERRQ(ierr);
720   PetscFunctionReturn(0);
721 }
722 EXTERN_C_END
723