xref: /petsc/src/ts/impls/arkimex/arkimex.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
1 /*
2   Code for timestepping with additive Runge-Kutta IMEX method
3 
4   Notes:
5   The general system is written as
6 
7   F(t,X,Xdot) = G(t,X)
8 
9   where F represents the stiff part of the physics and G represents the non-stiff part.
10 
11 */
12 #include <private/tsimpl.h>                /*I   "petscts.h"   I*/
13 
14 static const TSARKIMEXType TSARKIMEXDefault = TSARKIMEX2E;
15 static PetscBool TSARKIMEXRegisterAllCalled;
16 static PetscBool TSARKIMEXPackageInitialized;
17 
18 typedef struct _ARKTableau *ARKTableau;
19 struct _ARKTableau {
20   char *name;
21   PetscInt order;               /* Classical approximation order of the method */
22   PetscInt s;                   /* Number of stages */
23   PetscInt pinterp;             /* Interpolation order */
24   PetscReal *At,*bt,*ct;        /* Stiff tableau */
25   PetscReal *A,*b,*c;           /* Non-stiff tableau */
26   PetscReal *binterpt,*binterp; /* Dense output formula */
27 };
28 typedef struct _ARKTableauLink *ARKTableauLink;
29 struct _ARKTableauLink {
30   struct _ARKTableau tab;
31   ARKTableauLink next;
32 };
33 static ARKTableauLink ARKTableauList;
34 
35 typedef struct {
36   ARKTableau  tableau;
37   Vec         *Y;               /* States computed during the step */
38   Vec         *YdotI;           /* Time derivatives for the stiff part */
39   Vec         *YdotRHS;         /* Function evaluations for the non-stiff part */
40   Vec         Ydot;             /* Work vector holding Ydot during residual evaluation */
41   Vec         Work;             /* Generic work vector */
42   Vec         Z;                /* Ydot = shift(Y-Z) */
43   PetscScalar *work;            /* Scalar work */
44   PetscReal   shift;
45   PetscReal   stage_time;
46   PetscBool   imex;
47 } TS_ARKIMEX;
48 
49 /*MC
50      TSARKIMEX2D - Second order ARK IMEX scheme with L-stable implicit part.
51 
52      This method has one explicit stage and two implicit stages.
53 
54      Level: advanced
55 
56 .seealso: TSARKIMEX
57 M*/
58 /*MC
59      TSARKIMEX2E - Second order ARK IMEX scheme with L-stable implicit part.
60 
61      This method has one explicit stage and two implicit stages. It is is an optimal method developed by Emil Constantinescu.
62 
63      Level: advanced
64 
65 .seealso: TSARKIMEX
66 M*/
67 /*MC
68      TSARKIMEX3 - Third order ARK IMEX scheme with L-stable implicit part.
69 
70      This method has one explicit stage and three implicit stages.
71 
72      References:
73      Kennedy and Carpenter 2003.
74 
75      Level: advanced
76 
77 .seealso: TSARKIMEX
78 M*/
79 /*MC
80      TSARKIMEX4 - Fourth order ARK IMEX scheme with L-stable implicit part.
81 
82      This method has one explicit stage and four implicit stages.
83 
84      References:
85      Kennedy and Carpenter 2003.
86 
87      Level: advanced
88 
89 .seealso: TSARKIMEX
90 M*/
91 /*MC
92      TSARKIMEX5 - Fifth order ARK IMEX scheme with L-stable implicit part.
93 
94      This method has one explicit stage and five implicit stages.
95 
96      References:
97      Kennedy and Carpenter 2003.
98 
99      Level: advanced
100 
101 .seealso: TSARKIMEX
102 M*/
103 
104 #undef __FUNCT__
105 #define __FUNCT__ "TSARKIMEXRegisterAll"
106 /*@C
107   TSARKIMEXRegisterAll - Registers all of the additive Runge-Kutta implicit-explicit methods in TSARKIMEX
108 
109   Not Collective, but should be called by all processes which will need the schemes to be registered
110 
111   Level: advanced
112 
113 .keywords: TS, TSARKIMEX, register, all
114 
115 .seealso:  TSARKIMEXRegisterDestroy()
116 @*/
117 PetscErrorCode TSARKIMEXRegisterAll(void)
118 {
119   PetscErrorCode ierr;
120 
121   PetscFunctionBegin;
122   if (TSARKIMEXRegisterAllCalled) PetscFunctionReturn(0);
123   TSARKIMEXRegisterAllCalled = PETSC_TRUE;
124 
125   {
126     const PetscReal
127       A[3][3] = {{0,0,0},
128                  {0.41421356237309504880,0,0},
129                  {0.75,0.25,0}},
130       At[3][3] = {{0,0,0},
131                   {0.12132034355964257320,0.29289321881345247560,0},
132                   {0.20710678118654752440,0.50000000000000000000,0.29289321881345247560}},
133       binterpt[3][2] = {{1,-0.5},{0,0},{0,0.5}};
134     ierr = TSARKIMEXRegister(TSARKIMEX2D,2,3,&At[0][0],PETSC_NULL,PETSC_NULL,&A[0][0],PETSC_NULL,PETSC_NULL,2,binterpt[0],PETSC_NULL);CHKERRQ(ierr);
135   }
136   {                             /* Optimal for linear implicit part */
137     const PetscReal s2 = PetscSqrtReal((PetscReal)2.0),
138       A[3][3] = {{0,0,0},
139                  {2-s2,0,0},
140                  {(3-2*s2)/6,(3+2*s2)/6,0}},
141       At[3][3] = {{0,0,0},
142                   {1-1/s2,1-1/s2,0},
143                   {1/(2*s2),1/(2*s2),1-1/s2}},
144       binterpt[3][2] = {{1,-0.5},{0,0},{0,0.5}};
145     ierr = TSARKIMEXRegister(TSARKIMEX2E,2,3,&At[0][0],PETSC_NULL,PETSC_NULL,&A[0][0],PETSC_NULL,PETSC_NULL,2,binterpt[0],PETSC_NULL);CHKERRQ(ierr);
146   }
147   {
148     const PetscReal
149       A[4][4] = {{0,0,0,0},
150                  {1767732205903./2027836641118.,0,0,0},
151                  {5535828885825./10492691773637.,788022342437./10882634858940.,0,0},
152                  {6485989280629./16251701735622.,-4246266847089./9704473918619.,10755448449292./10357097424841.,0}},
153       At[4][4] = {{0,0,0,0},
154                   {1767732205903./4055673282236.,1767732205903./4055673282236.,0,0},
155                   {2746238789719./10658868560708.,-640167445237./6845629431997.,1767732205903./4055673282236.,0},
156                   {1471266399579./7840856788654.,-4482444167858./7529755066697.,11266239266428./11593286722821.,1767732205903./4055673282236.}},
157       binterpt[4][2] = {{4655552711362./22874653954995., -215264564351./13552729205753.},
158                         {-18682724506714./9892148508045.,17870216137069./13817060693119.},
159                         {34259539580243./13192909600954.,-28141676662227./17317692491321.},
160                         {584795268549./6622622206610.,   2508943948391./7218656332882.}};
161     ierr = TSARKIMEXRegister(TSARKIMEX3,3,4,&At[0][0],PETSC_NULL,PETSC_NULL,&A[0][0],PETSC_NULL,PETSC_NULL,2,binterpt[0],PETSC_NULL);CHKERRQ(ierr);
162   }
163   {
164     const PetscReal
165       A[6][6] = {{0,0,0,0,0,0},
166                  {1./2,0,0,0,0,0},
167                  {13861./62500.,6889./62500.,0,0,0,0},
168                  {-116923316275./2393684061468.,-2731218467317./15368042101831.,9408046702089./11113171139209.,0,0,0},
169                  {-451086348788./2902428689909.,-2682348792572./7519795681897.,12662868775082./11960479115383.,3355817975965./11060851509271.,0,0},
170                  {647845179188./3216320057751.,73281519250./8382639484533.,552539513391./3454668386233.,3354512671639./8306763924573.,4040./17871.,0}},
171       At[6][6] = {{0,0,0,0,0,0},
172                   {1./4,1./4,0,0,0,0},
173                   {8611./62500.,-1743./31250.,1./4,0,0,0},
174                   {5012029./34652500.,-654441./2922500.,174375./388108.,1./4,0,0},
175                   {15267082809./155376265600.,-71443401./120774400.,730878875./902184768.,2285395./8070912.,1./4,0},
176                   {82889./524892.,0,15625./83664.,69875./102672.,-2260./8211,1./4}},
177       binterpt[6][3] = {{6943876665148./7220017795957.,-54480133./30881146.,6818779379841./7100303317025.},
178                         {0,0,0},
179                         {7640104374378./9702883013639.,-11436875./14766696.,2173542590792./12501825683035.},
180                         {-20649996744609./7521556579894.,174696575./18121608.,-31592104683404./5083833661969.},
181                         {8854892464581./2390941311638.,-12120380./966161.,61146701046299./7138195549469.},
182                         {-11397109935349./6675773540249.,3843./706.,-17219254887155./4939391667607.}};
183     ierr = TSARKIMEXRegister(TSARKIMEX4,4,6,&At[0][0],PETSC_NULL,PETSC_NULL,&A[0][0],PETSC_NULL,PETSC_NULL,3,binterpt[0],PETSC_NULL);CHKERRQ(ierr);
184   }
185   {
186     const PetscReal
187       A[8][8] = {{0,0,0,0,0,0,0,0},
188                  {41./100,0,0,0,0,0,0,0},
189                  {367902744464./2072280473677.,677623207551./8224143866563.,0,0,0,0,0,0},
190                  {1268023523408./10340822734521.,0,1029933939417./13636558850479.,0,0,0,0,0},
191                  {14463281900351./6315353703477.,0,66114435211212./5879490589093.,-54053170152839./4284798021562.,0,0,0,0},
192                  {14090043504691./34967701212078.,0,15191511035443./11219624916014.,-18461159152457./12425892160975.,-281667163811./9011619295870.,0,0,0},
193                  {19230459214898./13134317526959.,0,21275331358303./2942455364971.,-38145345988419./4862620318723.,-1./8,-1./8,0,0},
194                  {-19977161125411./11928030595625.,0,-40795976796054./6384907823539.,177454434618887./12078138498510.,782672205425./8267701900261.,-69563011059811./9646580694205.,7356628210526./4942186776405.,0}},
195       At[8][8] = {{0,0,0,0,0,0,0,0},
196                   {41./200.,41./200.,0,0,0,0,0,0},
197                   {41./400.,-567603406766./11931857230679.,41./200.,0,0,0,0,0},
198                   {683785636431./9252920307686.,0,-110385047103./1367015193373.,41./200.,0,0,0,0},
199                   {3016520224154./10081342136671.,0,30586259806659./12414158314087.,-22760509404356./11113319521817.,41./200.,0,0,0},
200                   {218866479029./1489978393911.,0,638256894668./5436446318841.,-1179710474555./5321154724896.,-60928119172./8023461067671.,41./200.,0,0},
201                   {1020004230633./5715676835656.,0,25762820946817./25263940353407.,-2161375909145./9755907335909.,-211217309593./5846859502534.,-4269925059573./7827059040749.,41./200,0},
202                   {-872700587467./9133579230613.,0,0,22348218063261./9555858737531.,-1143369518992./8141816002931.,-39379526789629./19018526304540.,32727382324388./42900044865799.,41./200.}},
203       binterpt[8][3] = {{-17674230611817./10670229744614. ,  43486358583215./12773830924787. , -9257016797708./5021505065439.},
204                         {0                               ,  0                              , 0                            },
205                         {0                               ,  0                              , 0                            },
206                         {65168852399939./7868540260826.  ,  -91478233927265./11067650958493., 26096422576131./11239449250142.},
207                         {15494834004392./5936557850923.  ,  -79368583304911./10890268929626., 92396832856987./20362823103730.},
208                         {-99329723586156./26959484932159.,  -12239297817655./9152339842473. , 30029262896817./10175596800299.},
209                         {-19024464361622./5461577185407. ,  115839755401235./10719374521269., -26136350496073./3983972220547.},
210                         {-6511271360970./6095937251113.  ,  5843115559534./2180450260947.   , -5289405421727./3760307252460. }};
211     ierr = TSARKIMEXRegister(TSARKIMEX5,5,8,&At[0][0],PETSC_NULL,PETSC_NULL,&A[0][0],PETSC_NULL,PETSC_NULL,3,binterpt[0],PETSC_NULL);CHKERRQ(ierr);
212   }
213 
214   PetscFunctionReturn(0);
215 }
216 
217 #undef __FUNCT__
218 #define __FUNCT__ "TSARKIMEXRegisterDestroy"
219 /*@C
220    TSARKIMEXRegisterDestroy - Frees the list of schemes that were registered by TSARKIMEXRegister().
221 
222    Not Collective
223 
224    Level: advanced
225 
226 .keywords: TSARKIMEX, register, destroy
227 .seealso: TSARKIMEXRegister(), TSARKIMEXRegisterAll(), TSARKIMEXRegisterDynamic()
228 @*/
229 PetscErrorCode TSARKIMEXRegisterDestroy(void)
230 {
231   PetscErrorCode ierr;
232   ARKTableauLink link;
233 
234   PetscFunctionBegin;
235   while ((link = ARKTableauList)) {
236     ARKTableau t = &link->tab;
237     ARKTableauList = link->next;
238     ierr = PetscFree6(t->At,t->bt,t->ct,t->A,t->b,t->c);CHKERRQ(ierr);
239     ierr = PetscFree2(t->binterpt,t->binterp);CHKERRQ(ierr);
240     ierr = PetscFree(t->name);CHKERRQ(ierr);
241     ierr = PetscFree(link);CHKERRQ(ierr);
242   }
243   TSARKIMEXRegisterAllCalled = PETSC_FALSE;
244   PetscFunctionReturn(0);
245 }
246 
247 #undef __FUNCT__
248 #define __FUNCT__ "TSARKIMEXInitializePackage"
249 /*@C
250   TSARKIMEXInitializePackage - This function initializes everything in the TSARKIMEX package. It is called
251   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to TSCreate_ARKIMEX()
252   when using static libraries.
253 
254   Input Parameter:
255   path - The dynamic library path, or PETSC_NULL
256 
257   Level: developer
258 
259 .keywords: TS, TSARKIMEX, initialize, package
260 .seealso: PetscInitialize()
261 @*/
262 PetscErrorCode TSARKIMEXInitializePackage(const char path[])
263 {
264   PetscErrorCode ierr;
265 
266   PetscFunctionBegin;
267   if (TSARKIMEXPackageInitialized) PetscFunctionReturn(0);
268   TSARKIMEXPackageInitialized = PETSC_TRUE;
269   ierr = TSARKIMEXRegisterAll();CHKERRQ(ierr);
270   ierr = PetscRegisterFinalize(TSARKIMEXFinalizePackage);CHKERRQ(ierr);
271   PetscFunctionReturn(0);
272 }
273 
274 #undef __FUNCT__
275 #define __FUNCT__ "TSARKIMEXFinalizePackage"
276 /*@C
277   TSARKIMEXFinalizePackage - This function destroys everything in the TSARKIMEX package. It is
278   called from PetscFinalize().
279 
280   Level: developer
281 
282 .keywords: Petsc, destroy, package
283 .seealso: PetscFinalize()
284 @*/
285 PetscErrorCode TSARKIMEXFinalizePackage(void)
286 {
287   PetscErrorCode ierr;
288 
289   PetscFunctionBegin;
290   TSARKIMEXPackageInitialized = PETSC_FALSE;
291   ierr = TSARKIMEXRegisterDestroy();CHKERRQ(ierr);
292   PetscFunctionReturn(0);
293 }
294 
295 #undef __FUNCT__
296 #define __FUNCT__ "TSARKIMEXRegister"
297 /*@C
298    TSARKIMEXRegister - register an ARK IMEX scheme by providing the entries in the Butcher tableau and optionally embedded approximations and interpolation
299 
300    Not Collective, but the same schemes should be registered on all processes on which they will be used
301 
302    Input Parameters:
303 +  name - identifier for method
304 .  order - approximation order of method
305 .  s - number of stages, this is the dimension of the matrices below
306 .  At - Butcher table of stage coefficients for stiff part (dimension s*s, row-major)
307 .  bt - Butcher table for completing the stiff part of the step (dimension s; PETSC_NULL to use the last row of At)
308 .  ct - Abscissa of each stiff stage (dimension s, PETSC_NULL to use row sums of At)
309 .  A - Non-stiff stage coefficients (dimension s*s, row-major)
310 .  b - Non-stiff step completion table (dimension s; PETSC_NULL to use last row of At)
311 .  c - Non-stiff abscissa (dimension s; PETSC_NULL to use row sums of A)
312 .  pinterp - Order of the interpolation scheme, equal to the number of columns of binterpt and binterp
313 .  binterpt - Coefficients of the interpolation formula for the stiff part (dimension s*pinterp)
314 -  binterp - Coefficients of the interpolation formula for the non-stiff part (dimension s*pinterp; PETSC_NULL to reuse binterpt)
315 
316    Notes:
317    Several ARK IMEX methods are provided, this function is only needed to create new methods.
318 
319    Level: advanced
320 
321 .keywords: TS, register
322 
323 .seealso: TSARKIMEX
324 @*/
325 PetscErrorCode TSARKIMEXRegister(const TSARKIMEXType name,PetscInt order,PetscInt s,
326                                  const PetscReal At[],const PetscReal bt[],const PetscReal ct[],
327                                  const PetscReal A[],const PetscReal b[],const PetscReal c[],
328                                  PetscInt pinterp,const PetscReal binterpt[],const PetscReal binterp[])
329 {
330   PetscErrorCode ierr;
331   ARKTableauLink link;
332   ARKTableau t;
333   PetscInt i,j;
334 
335   PetscFunctionBegin;
336   ierr = PetscMalloc(sizeof(*link),&link);CHKERRQ(ierr);
337   ierr = PetscMemzero(link,sizeof(*link));CHKERRQ(ierr);
338   t = &link->tab;
339   ierr = PetscStrallocpy(name,&t->name);CHKERRQ(ierr);
340   t->order = order;
341   t->s = s;
342   ierr = PetscMalloc6(s*s,PetscReal,&t->At,s,PetscReal,&t->bt,s,PetscReal,&t->ct,s*s,PetscReal,&t->A,s,PetscReal,&t->b,s,PetscReal,&t->c);CHKERRQ(ierr);
343   ierr = PetscMemcpy(t->At,At,s*s*sizeof(At[0]));CHKERRQ(ierr);
344   ierr = PetscMemcpy(t->A,A,s*s*sizeof(A[0]));CHKERRQ(ierr);
345   if (bt) {ierr = PetscMemcpy(t->bt,bt,s*sizeof(bt[0]));CHKERRQ(ierr);}
346   else for (i=0; i<s; i++) t->bt[i] = At[(s-1)*s+i];
347   if (b) {ierr = PetscMemcpy(t->b,b,s*sizeof(b[0]));CHKERRQ(ierr);}
348   else for (i=0; i<s; i++) t->b[i] = At[(s-1)*s+i];
349   if (ct) {ierr = PetscMemcpy(t->ct,ct,s*sizeof(ct[0]));CHKERRQ(ierr);}
350   else for (i=0; i<s; i++) for (j=0,t->ct[i]=0; j<s; j++) t->ct[i] += At[i*s+j];
351   if (c) {ierr = PetscMemcpy(t->c,c,s*sizeof(c[0]));CHKERRQ(ierr);}
352   else for (i=0; i<s; i++) for (j=0,t->c[i]=0; j<s; j++) t->c[i] += A[i*s+j];
353   t->pinterp = pinterp;
354   ierr = PetscMalloc2(s*pinterp,PetscReal,&t->binterpt,s*pinterp,PetscReal,&t->binterp);CHKERRQ(ierr);
355   ierr = PetscMemcpy(t->binterpt,binterpt,s*pinterp*sizeof(binterpt[0]));CHKERRQ(ierr);
356   ierr = PetscMemcpy(t->binterp,binterp?binterp:binterpt,s*pinterp*sizeof(binterpt[0]));CHKERRQ(ierr);
357   link->next = ARKTableauList;
358   ARKTableauList = link;
359   PetscFunctionReturn(0);
360 }
361 
362 #undef __FUNCT__
363 #define __FUNCT__ "TSStep_ARKIMEX"
364 static PetscErrorCode TSStep_ARKIMEX(TS ts)
365 {
366   TS_ARKIMEX          *ark = (TS_ARKIMEX*)ts->data;
367   ARKTableau          tab  = ark->tableau;
368   const PetscInt      s    = tab->s;
369   const PetscReal     *At  = tab->At,*A = tab->A,*bt = tab->bt,*b = tab->b,*ct = tab->ct,*c = tab->c;
370   PetscScalar         *w   = ark->work;
371   Vec                 *Y   = ark->Y,*YdotI = ark->YdotI,*YdotRHS = ark->YdotRHS,Ydot = ark->Ydot,W = ark->Work,Z = ark->Z;
372   SNES                snes;
373   SNESConvergedReason snesreason;
374   PetscInt            i,j,its,lits;
375   PetscReal           next_time_step;
376   PetscReal           h,t;
377   PetscErrorCode      ierr;
378 
379   PetscFunctionBegin;
380   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
381   next_time_step = ts->time_step;
382   h = ts->time_step;
383   t = ts->ptime;
384 
385   for (i=0; i<s; i++) {
386     if (At[i*s+i] == 0) {           /* This stage is explicit */
387       ierr = VecCopy(ts->vec_sol,Y[i]);CHKERRQ(ierr);
388       for (j=0; j<i; j++) w[j] = -h*At[i*s+j];
389       ierr = VecMAXPY(Y[i],i,w,YdotI);CHKERRQ(ierr);
390       for (j=0; j<i; j++) w[j] = h*A[i*s+j];
391       ierr = VecMAXPY(Y[i],i,w,YdotRHS);CHKERRQ(ierr);
392     } else {
393       ark->stage_time = t + h*ct[i];
394       ark->shift = 1./(h*At[i*s+i]);
395       /* Affine part */
396       ierr = VecZeroEntries(W);CHKERRQ(ierr);
397       for (j=0; j<i; j++) w[j] = h*A[i*s+j];
398       ierr = VecMAXPY(W,i,w,YdotRHS);CHKERRQ(ierr);
399       /* Ydot = shift*(Y-Z) */
400       ierr = VecCopy(ts->vec_sol,Z);CHKERRQ(ierr);
401       for (j=0; j<i; j++) w[j] = -h*At[i*s+j];
402       ierr = VecMAXPY(Z,i,w,YdotI);CHKERRQ(ierr);
403       /* Initial guess taken from last stage */
404       ierr = VecCopy(i>0?Y[i-1]:ts->vec_sol,Y[i]);CHKERRQ(ierr);
405       ierr = SNESSolve(snes,W,Y[i]);CHKERRQ(ierr);
406       ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr);
407       ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr);
408       ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr);
409       ts->nonlinear_its += its; ts->linear_its += lits;
410       if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
411         ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
412         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);
413         PetscFunctionReturn(0);
414       }
415     }
416     ierr = VecZeroEntries(Ydot);CHKERRQ(ierr);
417     ierr = TSComputeIFunction(ts,t+h*ct[i],Y[i],Ydot,YdotI[i],ark->imex);CHKERRQ(ierr);
418     if (ark->imex) {
419       ierr = TSComputeRHSFunction(ts,t+h*c[i],Y[i],YdotRHS[i]);CHKERRQ(ierr);
420     } else {
421       ierr = VecZeroEntries(YdotRHS[i]);CHKERRQ(ierr);
422     }
423   }
424   for (j=0; j<s; j++) w[j] = -h*bt[j];
425   ierr = VecMAXPY(ts->vec_sol,s,w,YdotI);CHKERRQ(ierr);
426   for (j=0; j<s; j++) w[j] = h*b[j];
427   ierr = VecMAXPY(ts->vec_sol,s,w,YdotRHS);CHKERRQ(ierr);
428 
429   ts->ptime += ts->time_step;
430   ts->time_step = next_time_step;
431   ts->steps++;
432   PetscFunctionReturn(0);
433 }
434 
435 #undef __FUNCT__
436 #define __FUNCT__ "TSInterpolate_ARKIMEX"
437 static PetscErrorCode TSInterpolate_ARKIMEX(TS ts,PetscReal itime,Vec X)
438 {
439   TS_ARKIMEX *ark = (TS_ARKIMEX*)ts->data;
440   PetscInt s = ark->tableau->s,pinterp = ark->tableau->pinterp,i,j;
441   PetscReal tt,t = (itime - ts->ptime)/ts->time_step + 1; /* In the interval [0,1] */
442   PetscScalar *bt,*b;
443   const PetscReal *Bt = ark->tableau->binterpt,*B = ark->tableau->binterp;
444   PetscErrorCode ierr;
445 
446   PetscFunctionBegin;
447   if (!Bt || !B) SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_SUP,"TSARKIMEX %s does not have an interpolation formula",ark->tableau->name);
448   ierr = PetscMalloc2(s,PetscScalar,&bt,s,PetscScalar,&b);CHKERRQ(ierr);
449   for (i=0; i<s; i++) bt[i] = b[i] = 0;
450   for (j=0,tt=t; j<pinterp; j++,tt*=t) {
451     for (i=0; i<s; i++) {
452       bt[i] += ts->time_step * Bt[i*pinterp+j] * tt * -1.0;
453       b[i]  += ts->time_step * B[i*pinterp+j] * tt;
454     }
455   }
456   if (ark->tableau->At[0*s+0] != 0.0) SETERRQ(((PetscObject)ts)->comm,PETSC_ERR_SUP,"First stage not explicit so starting stage not saved");
457   ierr = VecCopy(ark->Y[0],X);CHKERRQ(ierr);
458   ierr = VecMAXPY(X,s,bt,ark->YdotI);CHKERRQ(ierr);
459   ierr = VecMAXPY(X,s,b,ark->YdotRHS);CHKERRQ(ierr);
460   ierr = PetscFree2(bt,b);CHKERRQ(ierr);
461   PetscFunctionReturn(0);
462 }
463 
464 /*------------------------------------------------------------*/
465 #undef __FUNCT__
466 #define __FUNCT__ "TSReset_ARKIMEX"
467 static PetscErrorCode TSReset_ARKIMEX(TS ts)
468 {
469   TS_ARKIMEX      *ark = (TS_ARKIMEX*)ts->data;
470   PetscInt        s;
471   PetscErrorCode  ierr;
472 
473   PetscFunctionBegin;
474   if (!ark->tableau) PetscFunctionReturn(0);
475    s = ark->tableau->s;
476   ierr = VecDestroyVecs(s,&ark->Y);CHKERRQ(ierr);
477   ierr = VecDestroyVecs(s,&ark->YdotI);CHKERRQ(ierr);
478   ierr = VecDestroyVecs(s,&ark->YdotRHS);CHKERRQ(ierr);
479   ierr = VecDestroy(&ark->Ydot);CHKERRQ(ierr);
480   ierr = VecDestroy(&ark->Work);CHKERRQ(ierr);
481   ierr = VecDestroy(&ark->Z);CHKERRQ(ierr);
482   ierr = PetscFree(ark->work);CHKERRQ(ierr);
483   PetscFunctionReturn(0);
484 }
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "TSDestroy_ARKIMEX"
488 static PetscErrorCode TSDestroy_ARKIMEX(TS ts)
489 {
490   PetscErrorCode  ierr;
491 
492   PetscFunctionBegin;
493   ierr = TSReset_ARKIMEX(ts);CHKERRQ(ierr);
494   ierr = PetscFree(ts->data);CHKERRQ(ierr);
495   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXGetType_C","",PETSC_NULL);CHKERRQ(ierr);
496   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXSetType_C","",PETSC_NULL);CHKERRQ(ierr);
497   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXSetFullyImplicit_C","",PETSC_NULL);CHKERRQ(ierr);
498   PetscFunctionReturn(0);
499 }
500 
501 /*
502   This defines the nonlinear equation that is to be solved with SNES
503   G(U) = F[t0+Theta*dt, U, (U-U0)*shift] = 0
504 */
505 #undef __FUNCT__
506 #define __FUNCT__ "SNESTSFormFunction_ARKIMEX"
507 static PetscErrorCode SNESTSFormFunction_ARKIMEX(SNES snes,Vec X,Vec F,TS ts)
508 {
509   TS_ARKIMEX     *ark = (TS_ARKIMEX*)ts->data;
510   PetscErrorCode ierr;
511 
512   PetscFunctionBegin;
513   ierr = VecAXPBYPCZ(ark->Ydot,-ark->shift,ark->shift,0,ark->Z,X);CHKERRQ(ierr); /* Ydot = shift*(X-Z) */
514   ierr = TSComputeIFunction(ts,ark->stage_time,X,ark->Ydot,F,ark->imex);CHKERRQ(ierr);
515   PetscFunctionReturn(0);
516 }
517 
518 #undef __FUNCT__
519 #define __FUNCT__ "SNESTSFormJacobian_ARKIMEX"
520 static PetscErrorCode SNESTSFormJacobian_ARKIMEX(SNES snes,Vec X,Mat *A,Mat *B,MatStructure *str,TS ts)
521 {
522   TS_ARKIMEX       *ark = (TS_ARKIMEX*)ts->data;
523   PetscErrorCode ierr;
524 
525   PetscFunctionBegin;
526   /* ark->Ydot has already been computed in SNESTSFormFunction_ARKIMEX (SNES guarantees this) */
527   ierr = TSComputeIJacobian(ts,ark->stage_time,X,ark->Ydot,ark->shift,A,B,str,PETSC_TRUE);CHKERRQ(ierr);
528   PetscFunctionReturn(0);
529 }
530 
531 #undef __FUNCT__
532 #define __FUNCT__ "TSSetUp_ARKIMEX"
533 static PetscErrorCode TSSetUp_ARKIMEX(TS ts)
534 {
535   TS_ARKIMEX     *ark = (TS_ARKIMEX*)ts->data;
536   ARKTableau     tab  = ark->tableau;
537   PetscInt       s = tab->s;
538   PetscErrorCode ierr;
539 
540   PetscFunctionBegin;
541   if (!ark->tableau) {
542     ierr = TSARKIMEXSetType(ts,TSARKIMEXDefault);CHKERRQ(ierr);
543   }
544   ierr = VecDuplicateVecs(ts->vec_sol,s,&ark->Y);CHKERRQ(ierr);
545   ierr = VecDuplicateVecs(ts->vec_sol,s,&ark->YdotI);CHKERRQ(ierr);
546   ierr = VecDuplicateVecs(ts->vec_sol,s,&ark->YdotRHS);CHKERRQ(ierr);
547   ierr = VecDuplicate(ts->vec_sol,&ark->Ydot);CHKERRQ(ierr);
548   ierr = VecDuplicate(ts->vec_sol,&ark->Work);CHKERRQ(ierr);
549   ierr = VecDuplicate(ts->vec_sol,&ark->Z);CHKERRQ(ierr);
550   ierr = PetscMalloc(s*sizeof(ark->work[0]),&ark->work);CHKERRQ(ierr);
551   PetscFunctionReturn(0);
552 }
553 /*------------------------------------------------------------*/
554 
555 #undef __FUNCT__
556 #define __FUNCT__ "TSSetFromOptions_ARKIMEX"
557 static PetscErrorCode TSSetFromOptions_ARKIMEX(TS ts)
558 {
559   TS_ARKIMEX     *ark = (TS_ARKIMEX*)ts->data;
560   PetscErrorCode ierr;
561   char           arktype[256];
562 
563   PetscFunctionBegin;
564   ierr = PetscOptionsHead("ARKIMEX ODE solver options");CHKERRQ(ierr);
565   {
566     ARKTableauLink link;
567     PetscInt count,choice;
568     PetscBool flg;
569     const char **namelist;
570     ierr = PetscStrncpy(arktype,TSARKIMEXDefault,sizeof arktype);CHKERRQ(ierr);
571     for (link=ARKTableauList,count=0; link; link=link->next,count++) ;
572     ierr = PetscMalloc(count*sizeof(char*),&namelist);CHKERRQ(ierr);
573     for (link=ARKTableauList,count=0; link; link=link->next,count++) namelist[count] = link->tab.name;
574     ierr = PetscOptionsEList("-ts_arkimex_type","Family of ARK IMEX method","TSARKIMEXSetType",(const char*const*)namelist,count,arktype,&choice,&flg);CHKERRQ(ierr);
575     ierr = TSARKIMEXSetType(ts,flg ? namelist[choice] : arktype);CHKERRQ(ierr);
576     ierr = PetscFree(namelist);CHKERRQ(ierr);
577     flg = (PetscBool)!ark->imex;
578     ierr = PetscOptionsBool("-ts_arkimex_fully_implicit","Solve the problem fully implicitly","TSARKIMEXSetFullyImplicit",flg,&flg,PETSC_NULL);CHKERRQ(ierr);
579     ark->imex = (PetscBool)!flg;
580     ierr = SNESSetFromOptions(ts->snes);CHKERRQ(ierr);
581   }
582   ierr = PetscOptionsTail();CHKERRQ(ierr);
583   PetscFunctionReturn(0);
584 }
585 
586 #undef __FUNCT__
587 #define __FUNCT__ "PetscFormatRealArray"
588 static PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
589 {
590   PetscErrorCode ierr;
591   PetscInt i;
592   size_t left,count;
593   char *p;
594 
595   PetscFunctionBegin;
596   for (i=0,p=buf,left=len; i<n; i++) {
597     ierr = PetscSNPrintfCount(p,left,fmt,&count,x[i]);CHKERRQ(ierr);
598     if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
599     left -= count;
600     p += count;
601     *p++ = ' ';
602   }
603   p[i ? 0 : -1] = 0;
604   PetscFunctionReturn(0);
605 }
606 
607 #undef __FUNCT__
608 #define __FUNCT__ "TSView_ARKIMEX"
609 static PetscErrorCode TSView_ARKIMEX(TS ts,PetscViewer viewer)
610 {
611   TS_ARKIMEX     *ark = (TS_ARKIMEX*)ts->data;
612   ARKTableau     tab = ark->tableau;
613   PetscBool      iascii;
614   PetscErrorCode ierr;
615 
616   PetscFunctionBegin;
617   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
618   if (iascii) {
619     const TSARKIMEXType arktype;
620     char buf[512];
621     ierr = TSARKIMEXGetType(ts,&arktype);CHKERRQ(ierr);
622     ierr = PetscViewerASCIIPrintf(viewer,"  ARK IMEX %s\n",arktype);CHKERRQ(ierr);
623     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->ct);CHKERRQ(ierr);
624     ierr = PetscViewerASCIIPrintf(viewer,"  Stiff abscissa       ct = %s\n",buf);CHKERRQ(ierr);
625     ierr = PetscFormatRealArray(buf,sizeof buf,"% 8.6f",tab->s,tab->c);CHKERRQ(ierr);
626     ierr = PetscViewerASCIIPrintf(viewer,"  Nonstiff abscissa     c = %s\n",buf);CHKERRQ(ierr);
627   }
628   ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr);
629   PetscFunctionReturn(0);
630 }
631 
632 #undef __FUNCT__
633 #define __FUNCT__ "TSARKIMEXSetType"
634 /*@C
635   TSARKIMEXSetType - Set the type of ARK IMEX scheme
636 
637   Logically collective
638 
639   Input Parameter:
640 +  ts - timestepping context
641 -  arktype - type of ARK-IMEX scheme
642 
643   Level: intermediate
644 
645 .seealso: TSARKIMEXGetType()
646 @*/
647 PetscErrorCode TSARKIMEXSetType(TS ts,const TSARKIMEXType arktype)
648 {
649   PetscErrorCode ierr;
650 
651   PetscFunctionBegin;
652   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
653   ierr = PetscTryMethod(ts,"TSARKIMEXSetType_C",(TS,const TSARKIMEXType),(ts,arktype));CHKERRQ(ierr);
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "TSARKIMEXGetType"
659 /*@C
660   TSARKIMEXGetType - Get the type of ARK IMEX scheme
661 
662   Logically collective
663 
664   Input Parameter:
665 .  ts - timestepping context
666 
667   Output Parameter:
668 .  arktype - type of ARK-IMEX scheme
669 
670   Level: intermediate
671 
672 .seealso: TSARKIMEXGetType()
673 @*/
674 PetscErrorCode TSARKIMEXGetType(TS ts,const TSARKIMEXType *arktype)
675 {
676   PetscErrorCode ierr;
677 
678   PetscFunctionBegin;
679   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
680   ierr = PetscUseMethod(ts,"TSARKIMEXGetType_C",(TS,const TSARKIMEXType*),(ts,arktype));CHKERRQ(ierr);
681   PetscFunctionReturn(0);
682 }
683 
684 #undef __FUNCT__
685 #define __FUNCT__ "TSARKIMEXSetFullyImplicit"
686 /*@C
687   TSARKIMEXSetFullyImplicit - Solve both parts of the equation implicitly
688 
689   Logically collective
690 
691   Input Parameter:
692 +  ts - timestepping context
693 -  flg - PETSC_TRUE for fully implicit
694 
695   Level: intermediate
696 
697 .seealso: TSARKIMEXGetType()
698 @*/
699 PetscErrorCode TSARKIMEXSetFullyImplicit(TS ts,PetscBool flg)
700 {
701   PetscErrorCode ierr;
702 
703   PetscFunctionBegin;
704   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
705   ierr = PetscTryMethod(ts,"TSARKIMEXSetFullyImplicit_C",(TS,PetscBool),(ts,flg));CHKERRQ(ierr);
706   PetscFunctionReturn(0);
707 }
708 
709 EXTERN_C_BEGIN
710 #undef __FUNCT__
711 #define __FUNCT__ "TSARKIMEXGetType_ARKIMEX"
712 PetscErrorCode  TSARKIMEXGetType_ARKIMEX(TS ts,const TSARKIMEXType *arktype)
713 {
714   TS_ARKIMEX *ark = (TS_ARKIMEX*)ts->data;
715   PetscErrorCode ierr;
716 
717   PetscFunctionBegin;
718   if (!ark->tableau) {ierr = TSARKIMEXSetType(ts,TSARKIMEXDefault);CHKERRQ(ierr);}
719   *arktype = ark->tableau->name;
720   PetscFunctionReturn(0);
721 }
722 #undef __FUNCT__
723 #define __FUNCT__ "TSARKIMEXSetType_ARKIMEX"
724 PetscErrorCode  TSARKIMEXSetType_ARKIMEX(TS ts,const TSARKIMEXType arktype)
725 {
726   TS_ARKIMEX *ark = (TS_ARKIMEX*)ts->data;
727   PetscErrorCode ierr;
728   PetscBool match;
729   ARKTableauLink link;
730 
731   PetscFunctionBegin;
732   if (ark->tableau) {
733     ierr = PetscStrcmp(ark->tableau->name,arktype,&match);CHKERRQ(ierr);
734     if (match) PetscFunctionReturn(0);
735   }
736   for (link = ARKTableauList; link; link=link->next) {
737     ierr = PetscStrcmp(link->tab.name,arktype,&match);CHKERRQ(ierr);
738     if (match) {
739       ierr = TSReset_ARKIMEX(ts);CHKERRQ(ierr);
740       ark->tableau = &link->tab;
741       PetscFunctionReturn(0);
742     }
743   }
744   SETERRQ1(((PetscObject)ts)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",arktype);
745   PetscFunctionReturn(0);
746 }
747 #undef __FUNCT__
748 #define __FUNCT__ "TSARKIMEXSetFullyImplicit_ARKIMEX"
749 PetscErrorCode  TSARKIMEXSetFullyImplicit_ARKIMEX(TS ts,PetscBool flg)
750 {
751   TS_ARKIMEX *ark = (TS_ARKIMEX*)ts->data;
752 
753   PetscFunctionBegin;
754   ark->imex = (PetscBool)!flg;
755   PetscFunctionReturn(0);
756 }
757 EXTERN_C_END
758 
759 /* ------------------------------------------------------------ */
760 /*MC
761       TSARKIMEX - ODE solver using Additive Runge-Kutta IMEX schemes
762 
763   These methods are intended for problems with well-separated time scales, especially when a slow scale is strongly
764   nonlinear such that it is expensive to solve with a fully implicit method. The user should provide the stiff part
765   of the equation using TSSetIFunction() and the non-stiff part with TSSetRHSFunction().
766 
767   Notes:
768   The default is TSARKIMEX2E, it can be changed with TSARKIMEXSetType() or -ts_arkimex_type
769 
770   This method currently only works with ODE, for which the stiff part G(t,X,Xdot) has the form Xdot + Ghat(t,X).
771 
772   Level: beginner
773 
774 .seealso:  TSCreate(), TS, TSSetType(), TSARKIMEXSetType(), TSARKIMEXGetType(), TSARKIMEXSetFullyImplicit(), TSARKIMEX2D, TTSARKIMEX2E, TSARKIMEX3,
775            TSARKIMEX4, TSARKIMEX5, TSARKIMEXType, TSARKIMEXRegister()
776 
777 M*/
778 EXTERN_C_BEGIN
779 #undef __FUNCT__
780 #define __FUNCT__ "TSCreate_ARKIMEX"
781 PetscErrorCode  TSCreate_ARKIMEX(TS ts)
782 {
783   TS_ARKIMEX       *th;
784   PetscErrorCode ierr;
785 
786   PetscFunctionBegin;
787 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
788   ierr = TSARKIMEXInitializePackage(PETSC_NULL);CHKERRQ(ierr);
789 #endif
790 
791   ts->ops->reset          = TSReset_ARKIMEX;
792   ts->ops->destroy        = TSDestroy_ARKIMEX;
793   ts->ops->view           = TSView_ARKIMEX;
794   ts->ops->setup          = TSSetUp_ARKIMEX;
795   ts->ops->step           = TSStep_ARKIMEX;
796   ts->ops->interpolate    = TSInterpolate_ARKIMEX;
797   ts->ops->setfromoptions = TSSetFromOptions_ARKIMEX;
798   ts->ops->snesfunction   = SNESTSFormFunction_ARKIMEX;
799   ts->ops->snesjacobian   = SNESTSFormJacobian_ARKIMEX;
800 
801   ierr = PetscNewLog(ts,TS_ARKIMEX,&th);CHKERRQ(ierr);
802   ts->data = (void*)th;
803   th->imex = PETSC_TRUE;
804 
805   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXGetType_C","TSARKIMEXGetType_ARKIMEX",TSARKIMEXGetType_ARKIMEX);CHKERRQ(ierr);
806   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXSetType_C","TSARKIMEXSetType_ARKIMEX",TSARKIMEXSetType_ARKIMEX);CHKERRQ(ierr);
807   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSARKIMEXSetFullyImplicit_C","TSARKIMEXSetFullyImplicit_ARKIMEX",TSARKIMEXSetFullyImplicit_ARKIMEX);CHKERRQ(ierr);
808   PetscFunctionReturn(0);
809 }
810 EXTERN_C_END
811