xref: /petsc/src/ts/impls/implicit/irk/irk.c (revision 3c859ba3a04a72e8efcb87bc7ffc046a6cbab413)
1 /*
2   Code for timestepping with implicit Runge-Kutta method
3 
4   Notes:
5   The general system is written as
6 
7   F(t,U,Udot) = 0
8 
9 */
10 #include <petsc/private/tsimpl.h>                /*I   "petscts.h"   I*/
11 #include <petscdm.h>
12 #include <petscdt.h>
13 
14 static TSIRKType         TSIRKDefault = TSIRKGAUSS;
15 static PetscBool         TSIRKRegisterAllCalled;
16 static PetscBool         TSIRKPackageInitialized;
17 static PetscFunctionList TSIRKList;
18 
19 struct _IRKTableau{
20   PetscReal   *A,*b,*c;
21   PetscScalar *A_inv,*A_inv_rowsum,*I_s;
22   PetscReal   *binterp;   /* Dense output formula */
23 };
24 
25 typedef struct _IRKTableau *IRKTableau;
26 
27 typedef struct {
28   char         *method_name;
29   PetscInt     order;            /* Classical approximation order of the method */
30   PetscInt     nstages;          /* Number of stages */
31   PetscBool    stiffly_accurate;
32   PetscInt     pinterp;          /* Interpolation order */
33   IRKTableau   tableau;
34   Vec          U0;               /* Backup vector */
35   Vec          Z;                /* Combined stage vector */
36   Vec          *Y;               /* States computed during the step */
37   Vec          Ydot;             /* Work vector holding time derivatives during residual evaluation */
38   Vec          U;                /* U is used to compute Ydot = shift(Y-U) */
39   Vec          *YdotI;           /* Work vectors to hold the residual evaluation */
40   Mat          TJ;               /* KAIJ matrix for the Jacobian of the combined system */
41   PetscScalar  *work;            /* Scalar work */
42   TSStepStatus status;
43   PetscBool    rebuild_completion;
44   PetscReal    ccfl;
45 } TS_IRK;
46 
47 /*@C
48    TSIRKTableauCreate - create the tableau for TSIRK and provide the entries
49 
50    Not Collective
51 
52    Input Parameters:
53 +  ts - timestepping context
54 .  nstages - number of stages, this is the dimension of the matrices below
55 .  A - stage coefficients (dimension nstages*nstages, row-major)
56 .  b - step completion table (dimension nstages)
57 .  c - abscissa (dimension nstages)
58 .  binterp - coefficients of the interpolation formula (dimension nstages)
59 .  A_inv - inverse of A (dimension nstages*nstages, row-major)
60 .  A_inv_rowsum - row sum of the inverse of A (dimension nstages)
61 -  I_s - identity matrix (dimension nstages*nstages)
62 
63    Level: advanced
64 
65 .seealso: TSIRK, TSIRKRegister()
66 @*/
67 PetscErrorCode TSIRKTableauCreate(TS ts,PetscInt nstages,const PetscReal *A,const PetscReal *b,const PetscReal *c,const PetscReal *binterp,const PetscScalar *A_inv,const PetscScalar *A_inv_rowsum,const PetscScalar *I_s)
68 {
69   TS_IRK         *irk = (TS_IRK*)ts->data;
70   IRKTableau     tab = irk->tableau;
71   PetscErrorCode ierr;
72 
73   PetscFunctionBegin;
74   irk->order = nstages;
75   ierr = PetscMalloc3(PetscSqr(nstages),&tab->A,PetscSqr(nstages),&tab->A_inv,PetscSqr(nstages),&tab->I_s);CHKERRQ(ierr);
76   ierr = PetscMalloc4(nstages,&tab->b,nstages,&tab->c,nstages,&tab->binterp,nstages,&tab->A_inv_rowsum);CHKERRQ(ierr);
77   ierr = PetscArraycpy(tab->A,A,PetscSqr(nstages));CHKERRQ(ierr);
78   ierr = PetscArraycpy(tab->b,b,nstages);CHKERRQ(ierr);
79   ierr = PetscArraycpy(tab->c,c,nstages);CHKERRQ(ierr);
80   /* optional coefficient arrays */
81   if (binterp) {
82     ierr = PetscArraycpy(tab->binterp,binterp,nstages);CHKERRQ(ierr);
83   }
84   if (A_inv) {
85     ierr = PetscArraycpy(tab->A_inv,A_inv,PetscSqr(nstages));CHKERRQ(ierr);
86   }
87   if (A_inv_rowsum) {
88     ierr = PetscArraycpy(tab->A_inv_rowsum,A_inv_rowsum,nstages);CHKERRQ(ierr);
89   }
90   if (I_s) {
91     ierr = PetscArraycpy(tab->I_s,I_s,PetscSqr(nstages));CHKERRQ(ierr);
92   }
93   PetscFunctionReturn(0);
94 }
95 
96 /* Arrays should be freed with PetscFree3(A,b,c) */
97 static PetscErrorCode TSIRKCreate_Gauss(TS ts)
98 {
99   PetscInt       nstages;
100   PetscReal      *gauss_A_real,*gauss_b,*b,*gauss_c;
101   PetscScalar    *gauss_A,*gauss_A_inv,*gauss_A_inv_rowsum,*I_s;
102   PetscScalar    *G0,*G1;
103   PetscInt       i,j;
104   Mat            G0mat,G1mat,Amat;
105   PetscErrorCode ierr;
106 
107   PetscFunctionBegin;
108   ierr = TSIRKGetNumStages(ts,&nstages);CHKERRQ(ierr);
109   ierr = PetscMalloc3(PetscSqr(nstages),&gauss_A_real,nstages,&gauss_b,nstages,&gauss_c);CHKERRQ(ierr);
110   ierr = PetscMalloc4(PetscSqr(nstages),&gauss_A,PetscSqr(nstages),&gauss_A_inv,nstages,&gauss_A_inv_rowsum,PetscSqr(nstages),&I_s);CHKERRQ(ierr);
111   ierr = PetscMalloc3(nstages,&b,PetscSqr(nstages),&G0,PetscSqr(nstages),&G1);CHKERRQ(ierr);
112   ierr = PetscDTGaussQuadrature(nstages,0.,1.,gauss_c,b);CHKERRQ(ierr);
113   for (i=0; i<nstages; i++) gauss_b[i] = b[i]; /* copy to possibly-complex array */
114 
115   /* A^T = G0^{-1} G1 */
116   for (i=0; i<nstages; i++) {
117     for (j=0; j<nstages; j++) {
118       G0[i*nstages+j] = PetscPowRealInt(gauss_c[i],j);
119       G1[i*nstages+j] = PetscPowRealInt(gauss_c[i],j+1)/(j+1);
120     }
121   }
122   /* The arrays above are row-aligned, but we create dense matrices as the transpose */
123   ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,G0,&G0mat);CHKERRQ(ierr);
124   ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,G1,&G1mat);CHKERRQ(ierr);
125   ierr = MatCreateSeqDense(PETSC_COMM_SELF,nstages,nstages,gauss_A,&Amat);CHKERRQ(ierr);
126   ierr = MatLUFactor(G0mat,NULL,NULL,NULL);CHKERRQ(ierr);
127   ierr = MatMatSolve(G0mat,G1mat,Amat);CHKERRQ(ierr);
128   ierr = MatTranspose(Amat,MAT_INPLACE_MATRIX,&Amat);CHKERRQ(ierr);
129   for (i=0; i<nstages; i++)
130     for (j=0; j<nstages; j++)
131       gauss_A_real[i*nstages+j] = PetscRealPart(gauss_A[i*nstages+j]);
132 
133   ierr = MatDestroy(&G0mat);CHKERRQ(ierr);
134   ierr = MatDestroy(&G1mat);CHKERRQ(ierr);
135   ierr = MatDestroy(&Amat);CHKERRQ(ierr);
136   ierr = PetscFree3(b,G0,G1);CHKERRQ(ierr);
137 
138   {/* Invert A */
139     /* PETSc does not provide a routine to calculate the inverse of a general matrix.
140      * To get the inverse of A, we form a sequential BAIJ matrix from it, consisting of a single block with block size
141      * equal to the dimension of A, and then use MatInvertBlockDiagonal(). */
142     Mat               A_baij;
143     PetscInt          idxm[1]={0},idxn[1]={0};
144     const PetscScalar *A_inv;
145 
146     ierr = MatCreateSeqBAIJ(PETSC_COMM_SELF,nstages,nstages,nstages,1,NULL,&A_baij);CHKERRQ(ierr);
147     ierr = MatSetOption(A_baij,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
148     ierr = MatSetValuesBlocked(A_baij,1,idxm,1,idxn,gauss_A,INSERT_VALUES);CHKERRQ(ierr);
149     ierr = MatAssemblyBegin(A_baij,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
150     ierr = MatAssemblyEnd(A_baij,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
151     ierr = MatInvertBlockDiagonal(A_baij,&A_inv);CHKERRQ(ierr);
152     ierr = PetscMemcpy(gauss_A_inv,A_inv,nstages*nstages*sizeof(PetscScalar));CHKERRQ(ierr);
153     ierr = MatDestroy(&A_baij);CHKERRQ(ierr);
154   }
155 
156   /* Compute row sums A_inv_rowsum and identity I_s */
157   for (i=0; i<nstages; i++) {
158     gauss_A_inv_rowsum[i] = 0;
159     for (j=0; j<nstages; j++) {
160       gauss_A_inv_rowsum[i] += gauss_A_inv[i+nstages*j];
161       I_s[i+nstages*j] = 1.*(i == j);
162     }
163   }
164   ierr = TSIRKTableauCreate(ts,nstages,gauss_A_real,gauss_b,gauss_c,NULL,gauss_A_inv,gauss_A_inv_rowsum,I_s);CHKERRQ(ierr);
165   ierr = PetscFree3(gauss_A_real,gauss_b,gauss_c);CHKERRQ(ierr);
166   ierr = PetscFree4(gauss_A,gauss_A_inv,gauss_A_inv_rowsum,I_s);CHKERRQ(ierr);
167   PetscFunctionReturn(0);
168 }
169 
170 /*@C
171    TSIRKRegister -  adds a TSIRK implementation
172 
173    Not Collective
174 
175    Input Parameters:
176 +  sname - name of user-defined IRK scheme
177 -  function - function to create method context
178 
179    Notes:
180    TSIRKRegister() may be called multiple times to add several user-defined families.
181 
182    Sample usage:
183 .vb
184    TSIRKRegister("my_scheme",MySchemeCreate);
185 .ve
186 
187    Then, your scheme can be chosen with the procedural interface via
188 $     TSIRKSetType(ts,"my_scheme")
189    or at runtime via the option
190 $     -ts_irk_type my_scheme
191 
192    Level: advanced
193 
194 .seealso: TSIRKRegisterAll()
195 @*/
196 PetscErrorCode TSIRKRegister(const char sname[],PetscErrorCode (*function)(TS))
197 {
198   PetscErrorCode ierr;
199 
200   PetscFunctionBegin;
201   ierr = TSIRKInitializePackage();CHKERRQ(ierr);
202   ierr = PetscFunctionListAdd(&TSIRKList,sname,function);CHKERRQ(ierr);
203   PetscFunctionReturn(0);
204 }
205 
206 /*@C
207   TSIRKRegisterAll - Registers all of the implicit Runge-Kutta methods in TSIRK
208 
209   Not Collective, but should be called by all processes which will need the schemes to be registered
210 
211   Level: advanced
212 
213 .seealso:  TSIRKRegisterDestroy()
214 @*/
215 PetscErrorCode TSIRKRegisterAll(void)
216 {
217   PetscErrorCode ierr;
218 
219   PetscFunctionBegin;
220   if (TSIRKRegisterAllCalled) PetscFunctionReturn(0);
221   TSIRKRegisterAllCalled = PETSC_TRUE;
222 
223   ierr = TSIRKRegister(TSIRKGAUSS,TSIRKCreate_Gauss);CHKERRQ(ierr);
224   PetscFunctionReturn(0);
225 }
226 
227 /*@C
228    TSIRKRegisterDestroy - Frees the list of schemes that were registered by TSIRKRegister().
229 
230    Not Collective
231 
232    Level: advanced
233 
234 .seealso: TSIRKRegister(), TSIRKRegisterAll()
235 @*/
236 PetscErrorCode TSIRKRegisterDestroy(void)
237 {
238   PetscFunctionBegin;
239   TSIRKRegisterAllCalled = PETSC_FALSE;
240   PetscFunctionReturn(0);
241 }
242 
243 /*@C
244   TSIRKInitializePackage - This function initializes everything in the TSIRK package. It is called
245   from TSInitializePackage().
246 
247   Level: developer
248 
249 .seealso: PetscInitialize()
250 @*/
251 PetscErrorCode TSIRKInitializePackage(void)
252 {
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   if (TSIRKPackageInitialized) PetscFunctionReturn(0);
257   TSIRKPackageInitialized = PETSC_TRUE;
258   ierr = TSIRKRegisterAll();CHKERRQ(ierr);
259   ierr = PetscRegisterFinalize(TSIRKFinalizePackage);CHKERRQ(ierr);
260   PetscFunctionReturn(0);
261 }
262 
263 /*@C
264   TSIRKFinalizePackage - This function destroys everything in the TSIRK package. It is
265   called from PetscFinalize().
266 
267   Level: developer
268 
269 .seealso: PetscFinalize()
270 @*/
271 PetscErrorCode TSIRKFinalizePackage(void)
272 {
273   PetscErrorCode ierr;
274 
275   PetscFunctionBegin;
276   ierr = PetscFunctionListDestroy(&TSIRKList);CHKERRQ(ierr);
277   TSIRKPackageInitialized = PETSC_FALSE;
278   PetscFunctionReturn(0);
279 }
280 
281 /*
282  This function can be called before or after ts->vec_sol has been updated.
283 */
284 static PetscErrorCode TSEvaluateStep_IRK(TS ts,PetscInt order,Vec U,PetscBool *done)
285 {
286   TS_IRK         *irk = (TS_IRK*)ts->data;
287   IRKTableau     tab = irk->tableau;
288   Vec            *YdotI = irk->YdotI;
289   PetscScalar    *w = irk->work;
290   PetscReal      h;
291   PetscInt       j;
292   PetscErrorCode ierr;
293 
294   PetscFunctionBegin;
295   switch (irk->status) {
296   case TS_STEP_INCOMPLETE:
297   case TS_STEP_PENDING:
298     h = ts->time_step; break;
299   case TS_STEP_COMPLETE:
300     h = ts->ptime - ts->ptime_prev; break;
301   default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus");
302   }
303 
304   ierr = VecCopy(ts->vec_sol,U);CHKERRQ(ierr);
305   for (j=0; j<irk->nstages; j++) w[j] = h*tab->b[j];
306   ierr = VecMAXPY(U,irk->nstages,w,YdotI);CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 
310 static PetscErrorCode TSRollBack_IRK(TS ts)
311 {
312   TS_IRK         *irk = (TS_IRK*)ts->data;
313   PetscErrorCode ierr;
314 
315   PetscFunctionBegin;
316   ierr = VecCopy(irk->U0,ts->vec_sol);CHKERRQ(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 static PetscErrorCode TSStep_IRK(TS ts)
321 {
322   TS_IRK          *irk = (TS_IRK*)ts->data;
323   IRKTableau      tab = irk->tableau;
324   PetscScalar     *A_inv = tab->A_inv,*A_inv_rowsum = tab->A_inv_rowsum;
325   const PetscInt  nstages = irk->nstages;
326   SNES            snes;
327   PetscInt        i,j,its,lits,bs;
328   TSAdapt         adapt;
329   PetscInt        rejections = 0;
330   PetscBool       accept = PETSC_TRUE;
331   PetscReal       next_time_step = ts->time_step;
332   PetscErrorCode  ierr;
333 
334   PetscFunctionBegin;
335   if (!ts->steprollback) {
336     ierr = VecCopy(ts->vec_sol,irk->U0);CHKERRQ(ierr);
337   }
338   ierr = VecGetBlockSize(ts->vec_sol,&bs);CHKERRQ(ierr);
339   for (i=0; i<nstages; i++) {
340     ierr = VecStrideScatter(ts->vec_sol,i*bs,irk->Z,INSERT_VALUES);CHKERRQ(ierr);
341   }
342 
343   irk->status = TS_STEP_INCOMPLETE;
344   while (!ts->reason && irk->status != TS_STEP_COMPLETE) {
345     ierr = VecCopy(ts->vec_sol,irk->U);CHKERRQ(ierr);
346     ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
347     ierr = SNESSolve(snes,NULL,irk->Z);CHKERRQ(ierr);
348     ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr);
349     ierr = SNESGetLinearSolveIterations(snes,&lits);CHKERRQ(ierr);
350     ts->snes_its += its; ts->ksp_its += lits;
351     ierr = VecStrideGatherAll(irk->Z,irk->Y,INSERT_VALUES);CHKERRQ(ierr);
352     for (i=0; i<nstages; i++) {
353       ierr = VecZeroEntries(irk->YdotI[i]);CHKERRQ(ierr);
354       for (j=0; j<nstages; j++) {
355         ierr = VecAXPY(irk->YdotI[i],A_inv[i+j*nstages]/ts->time_step,irk->Y[j]);CHKERRQ(ierr);
356       }
357       ierr = VecAXPY(irk->YdotI[i],-A_inv_rowsum[i]/ts->time_step,irk->U);CHKERRQ(ierr);
358     }
359     irk->status = TS_STEP_INCOMPLETE;
360     ierr = TSEvaluateStep_IRK(ts,irk->order,ts->vec_sol,NULL);CHKERRQ(ierr);
361     irk->status = TS_STEP_PENDING;
362     ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
363     ierr = TSAdaptChoose(adapt,ts,ts->time_step,NULL,&next_time_step,&accept);CHKERRQ(ierr);
364     irk->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
365     if (!accept) {
366       ierr = TSRollBack_IRK(ts);CHKERRQ(ierr);
367       ts->time_step = next_time_step;
368       goto reject_step;
369     }
370 
371     ts->ptime += ts->time_step;
372     ts->time_step = next_time_step;
373     break;
374   reject_step:
375     ts->reject++; accept = PETSC_FALSE;
376     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
377       ts->reason = TS_DIVERGED_STEP_REJECTED;
378       ierr = PetscInfo(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,rejections);CHKERRQ(ierr);
379     }
380   }
381   PetscFunctionReturn(0);
382 }
383 
384 static PetscErrorCode TSInterpolate_IRK(TS ts,PetscReal itime,Vec U)
385 {
386   TS_IRK          *irk = (TS_IRK*)ts->data;
387   PetscInt        nstages = irk->nstages,pinterp = irk->pinterp,i,j;
388   PetscReal       h;
389   PetscReal       tt,t;
390   PetscScalar     *bt;
391   const PetscReal *B = irk->tableau->binterp;
392   PetscErrorCode  ierr;
393 
394   PetscFunctionBegin;
395   PetscCheckFalse(!B,PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSIRK %s does not have an interpolation formula",irk->method_name);
396   switch (irk->status) {
397   case TS_STEP_INCOMPLETE:
398   case TS_STEP_PENDING:
399     h = ts->time_step;
400     t = (itime - ts->ptime)/h;
401     break;
402   case TS_STEP_COMPLETE:
403     h = ts->ptime - ts->ptime_prev;
404     t = (itime - ts->ptime)/h + 1; /* In the interval [0,1] */
405     break;
406   default: SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_PLIB,"Invalid TSStepStatus");
407   }
408   ierr = PetscMalloc1(nstages,&bt);CHKERRQ(ierr);
409   for (i=0; i<nstages; i++) bt[i] = 0;
410   for (j=0,tt=t; j<pinterp; j++,tt*=t) {
411     for (i=0; i<nstages; i++) {
412       bt[i] += h * B[i*pinterp+j] * tt;
413     }
414   }
415   ierr = VecMAXPY(U,nstages,bt,irk->YdotI);CHKERRQ(ierr);
416   PetscFunctionReturn(0);
417 }
418 
419 static PetscErrorCode TSIRKTableauReset(TS ts)
420 {
421   TS_IRK         *irk = (TS_IRK*)ts->data;
422   IRKTableau     tab = irk->tableau;
423   PetscErrorCode ierr;
424 
425   PetscFunctionBegin;
426   if (!tab) PetscFunctionReturn(0);
427   ierr = PetscFree3(tab->A,tab->A_inv,tab->I_s);CHKERRQ(ierr);
428   ierr = PetscFree4(tab->b,tab->c,tab->binterp,tab->A_inv_rowsum);CHKERRQ(ierr);
429   PetscFunctionReturn(0);
430 }
431 
432 static PetscErrorCode TSReset_IRK(TS ts)
433 {
434   TS_IRK         *irk = (TS_IRK*)ts->data;
435   PetscErrorCode ierr;
436 
437   PetscFunctionBegin;
438   ierr = TSIRKTableauReset(ts);CHKERRQ(ierr);
439   if (irk->tableau) {
440     ierr = PetscFree(irk->tableau);CHKERRQ(ierr);
441   }
442   if (irk->method_name) {
443     ierr = PetscFree(irk->method_name);CHKERRQ(ierr);
444   }
445   if (irk->work) {
446     ierr = PetscFree(irk->work);CHKERRQ(ierr);
447   }
448   ierr = VecDestroyVecs(irk->nstages,&irk->Y);CHKERRQ(ierr);
449   ierr = VecDestroyVecs(irk->nstages,&irk->YdotI);CHKERRQ(ierr);
450   ierr = VecDestroy(&irk->Ydot);CHKERRQ(ierr);
451   ierr = VecDestroy(&irk->Z);CHKERRQ(ierr);
452   ierr = VecDestroy(&irk->U);CHKERRQ(ierr);
453   ierr = VecDestroy(&irk->U0);CHKERRQ(ierr);
454   ierr = MatDestroy(&irk->TJ);CHKERRQ(ierr);
455   PetscFunctionReturn(0);
456 }
457 
458 static PetscErrorCode TSIRKGetVecs(TS ts,DM dm,Vec *U)
459 {
460   TS_IRK         *irk = (TS_IRK*)ts->data;
461   PetscErrorCode ierr;
462 
463   PetscFunctionBegin;
464   if (U) {
465     if (dm && dm != ts->dm) {
466       ierr = DMGetNamedGlobalVector(dm,"TSIRK_U",U);CHKERRQ(ierr);
467     } else *U = irk->U;
468   }
469   PetscFunctionReturn(0);
470 }
471 
472 static PetscErrorCode TSIRKRestoreVecs(TS ts,DM dm,Vec *U)
473 {
474   PetscErrorCode ierr;
475 
476   PetscFunctionBegin;
477   if (U) {
478     if (dm && dm != ts->dm) {
479       ierr = DMRestoreNamedGlobalVector(dm,"TSIRK_U",U);CHKERRQ(ierr);
480     }
481   }
482   PetscFunctionReturn(0);
483 }
484 
485 /*
486   This defines the nonlinear equations that is to be solved with SNES
487     G[e\otimes t + C*dt, Z, Zdot] = 0
488     Zdot = (In \otimes S)*Z - (In \otimes Se) U
489   where S = 1/(dt*A)
490 */
491 static PetscErrorCode SNESTSFormFunction_IRK(SNES snes,Vec ZC,Vec FC,TS ts)
492 {
493   TS_IRK            *irk = (TS_IRK*)ts->data;
494   IRKTableau        tab  = irk->tableau;
495   const PetscInt    nstages = irk->nstages;
496   const PetscReal   *c = tab->c;
497   const PetscScalar *A_inv = tab->A_inv,*A_inv_rowsum = tab->A_inv_rowsum;
498   DM                dm,dmsave;
499   Vec               U,*YdotI = irk->YdotI,Ydot = irk->Ydot,*Y = irk->Y;
500   PetscReal         h = ts->time_step;
501   PetscInt          i,j;
502   PetscErrorCode    ierr;
503 
504   PetscFunctionBegin;
505   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
506   ierr = TSIRKGetVecs(ts,dm,&U);CHKERRQ(ierr);
507   ierr = VecStrideGatherAll(ZC,Y,INSERT_VALUES);CHKERRQ(ierr);
508   dmsave = ts->dm;
509   ts->dm = dm;
510   for (i=0; i<nstages; i++) {
511     ierr = VecZeroEntries(Ydot);CHKERRQ(ierr);
512     for (j=0; j<nstages; j++) {
513       ierr = VecAXPY(Ydot,A_inv[j*nstages+i]/h,Y[j]);CHKERRQ(ierr);
514     }
515     ierr = VecAXPY(Ydot,-A_inv_rowsum[i]/h,U);CHKERRQ(ierr); /* Ydot = (S \otimes In)*Z - (Se \otimes In) U */
516     ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step*c[i],Y[i],Ydot,YdotI[i],PETSC_FALSE);CHKERRQ(ierr);
517   }
518   ierr = VecStrideScatterAll(YdotI,FC,INSERT_VALUES);CHKERRQ(ierr);
519   ts->dm = dmsave;
520   ierr   = TSIRKRestoreVecs(ts,dm,&U);CHKERRQ(ierr);
521   PetscFunctionReturn(0);
522 }
523 
524 /*
525    For explicit ODE, the Jacobian is
526      JC = I_n \otimes S - J \otimes I_s
527    For DAE, the Jacobian is
528      JC = M_n \otimes S - J \otimes I_s
529 */
530 static PetscErrorCode SNESTSFormJacobian_IRK(SNES snes,Vec ZC,Mat JC,Mat JCpre,TS ts)
531 {
532   TS_IRK          *irk = (TS_IRK*)ts->data;
533   IRKTableau      tab  = irk->tableau;
534   const PetscInt  nstages = irk->nstages;
535   const PetscReal *c = tab->c;
536   DM              dm,dmsave;
537   Vec             *Y = irk->Y,Ydot = irk->Ydot;
538   Mat             J;
539   PetscScalar     *S;
540   PetscInt        i,j,bs;
541   PetscErrorCode  ierr;
542 
543   PetscFunctionBegin;
544   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
545   /* irk->Ydot has already been computed in SNESTSFormFunction_IRK (SNES guarantees this) */
546   dmsave = ts->dm;
547   ts->dm = dm;
548   ierr = VecGetBlockSize(Y[nstages-1],&bs);CHKERRQ(ierr);
549   if (ts->equation_type <= TS_EQ_ODE_EXPLICIT) { /* Support explicit formulas only */
550     ierr = VecStrideGather(ZC,(nstages-1)*bs,Y[nstages-1],INSERT_VALUES);CHKERRQ(ierr);
551     ierr = MatKAIJGetAIJ(JC,&J);CHKERRQ(ierr);
552     ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step*c[nstages-1],Y[nstages-1],Ydot,0,J,J,PETSC_FALSE);CHKERRQ(ierr);
553     ierr = MatKAIJGetS(JC,NULL,NULL,&S);CHKERRQ(ierr);
554     for (i=0; i<nstages; i++)
555       for (j=0; j<nstages; j++)
556         S[i+nstages*j] = tab->A_inv[i+nstages*j]/ts->time_step;
557     ierr = MatKAIJRestoreS(JC,&S);CHKERRQ(ierr);
558   } else SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSIRK %s does not support implicit formula",irk->method_name); /* TODO: need the mass matrix for DAE  */
559   ts->dm = dmsave;
560   PetscFunctionReturn(0);
561 }
562 
563 static PetscErrorCode DMCoarsenHook_TSIRK(DM fine,DM coarse,void *ctx)
564 {
565   PetscFunctionBegin;
566   PetscFunctionReturn(0);
567 }
568 
569 static PetscErrorCode DMRestrictHook_TSIRK(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
570 {
571   TS             ts = (TS)ctx;
572   Vec            U,U_c;
573   PetscErrorCode ierr;
574 
575   PetscFunctionBegin;
576   ierr = TSIRKGetVecs(ts,fine,&U);CHKERRQ(ierr);
577   ierr = TSIRKGetVecs(ts,coarse,&U_c);CHKERRQ(ierr);
578   ierr = MatRestrict(restrct,U,U_c);CHKERRQ(ierr);
579   ierr = VecPointwiseMult(U_c,rscale,U_c);CHKERRQ(ierr);
580   ierr = TSIRKRestoreVecs(ts,fine,&U);CHKERRQ(ierr);
581   ierr = TSIRKRestoreVecs(ts,coarse,&U_c);CHKERRQ(ierr);
582   PetscFunctionReturn(0);
583 }
584 
585 static PetscErrorCode DMSubDomainHook_TSIRK(DM dm,DM subdm,void *ctx)
586 {
587   PetscFunctionBegin;
588   PetscFunctionReturn(0);
589 }
590 
591 static PetscErrorCode DMSubDomainRestrictHook_TSIRK(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
592 {
593   TS             ts = (TS)ctx;
594   Vec            U,U_c;
595   PetscErrorCode ierr;
596 
597   PetscFunctionBegin;
598   ierr = TSIRKGetVecs(ts,dm,&U);CHKERRQ(ierr);
599   ierr = TSIRKGetVecs(ts,subdm,&U_c);CHKERRQ(ierr);
600 
601   ierr = VecScatterBegin(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
602   ierr = VecScatterEnd(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
603 
604   ierr = TSIRKRestoreVecs(ts,dm,&U);CHKERRQ(ierr);
605   ierr = TSIRKRestoreVecs(ts,subdm,&U_c);CHKERRQ(ierr);
606   PetscFunctionReturn(0);
607 }
608 
609 static PetscErrorCode TSSetUp_IRK(TS ts)
610 {
611   TS_IRK         *irk = (TS_IRK*)ts->data;
612   IRKTableau     tab = irk->tableau;
613   DM             dm;
614   Mat            J;
615   Vec            R;
616   const PetscInt nstages = irk->nstages;
617   PetscInt       vsize,bs;
618   PetscErrorCode ierr;
619 
620   PetscFunctionBegin;
621   if (!irk->work) {
622     ierr = PetscMalloc1(irk->nstages,&irk->work);CHKERRQ(ierr);
623   }
624   if (!irk->Y) {
625     ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->Y);CHKERRQ(ierr);
626   }
627   if (!irk->YdotI) {
628     ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->YdotI);CHKERRQ(ierr);
629   }
630   if (!irk->Ydot) {
631     ierr = VecDuplicate(ts->vec_sol,&irk->Ydot);CHKERRQ(ierr);
632   }
633   if (!irk->U) {
634     ierr = VecDuplicate(ts->vec_sol,&irk->U);CHKERRQ(ierr);
635   }
636   if (!irk->U0) {
637     ierr = VecDuplicate(ts->vec_sol,&irk->U0);CHKERRQ(ierr);
638   }
639   if (!irk->Z) {
640     ierr = VecCreate(PetscObjectComm((PetscObject)ts->vec_sol),&irk->Z);CHKERRQ(ierr);
641     ierr = VecGetSize(ts->vec_sol,&vsize);CHKERRQ(ierr);
642     ierr = VecSetSizes(irk->Z,PETSC_DECIDE,vsize*irk->nstages);CHKERRQ(ierr);
643     ierr = VecGetBlockSize(ts->vec_sol,&bs);CHKERRQ(ierr);
644     ierr = VecSetBlockSize(irk->Z,irk->nstages*bs);CHKERRQ(ierr);
645     ierr = VecSetFromOptions(irk->Z);CHKERRQ(ierr);
646   }
647   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
648   ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr);
649   ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr);
650 
651   ierr = TSGetSNES(ts,&ts->snes);CHKERRQ(ierr);
652   ierr = VecDuplicate(irk->Z,&R);CHKERRQ(ierr);
653   ierr = SNESSetFunction(ts->snes,R,SNESTSFormFunction,ts);CHKERRQ(ierr);
654   ierr = TSGetIJacobian(ts,&J,NULL,NULL,NULL);CHKERRQ(ierr);
655   if (!irk->TJ) {
656     /* Create the KAIJ matrix for solving the stages */
657     ierr = MatCreateKAIJ(J,nstages,nstages,tab->A_inv,tab->I_s,&irk->TJ);CHKERRQ(ierr);
658   }
659   ierr = SNESSetJacobian(ts->snes,irk->TJ,irk->TJ,SNESTSFormJacobian,ts);CHKERRQ(ierr);
660   ierr = VecDestroy(&R);CHKERRQ(ierr);
661   PetscFunctionReturn(0);
662 }
663 
664 static PetscErrorCode TSSetFromOptions_IRK(PetscOptionItems *PetscOptionsObject,TS ts)
665 {
666   TS_IRK         *irk = (TS_IRK*)ts->data;
667   char           tname[256] = TSIRKGAUSS;
668   PetscErrorCode ierr;
669 
670   PetscFunctionBegin;
671   ierr = PetscOptionsHead(PetscOptionsObject,"IRK ODE solver options");CHKERRQ(ierr);
672   {
673     PetscBool flg1,flg2;
674     ierr = PetscOptionsInt("-ts_irk_nstages","Stages of the IRK method","TSIRKSetNumStages",irk->nstages,&irk->nstages,&flg1);CHKERRQ(ierr);
675     ierr = PetscOptionsFList("-ts_irk_type","Type of IRK method","TSIRKSetType",TSIRKList,irk->method_name[0] ? irk->method_name : tname,tname,sizeof(tname),&flg2);CHKERRQ(ierr);
676     if (flg1 ||flg2 || !irk->method_name[0]) { /* Create the method tableau after nstages or method is set */
677       ierr = TSIRKSetType(ts,tname);CHKERRQ(ierr);
678     }
679   }
680   ierr = PetscOptionsTail();CHKERRQ(ierr);
681   PetscFunctionReturn(0);
682 }
683 
684 static PetscErrorCode TSView_IRK(TS ts,PetscViewer viewer)
685 {
686   TS_IRK         *irk = (TS_IRK*)ts->data;
687   PetscBool      iascii;
688   PetscErrorCode ierr;
689 
690   PetscFunctionBegin;
691   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
692   if (iascii) {
693     IRKTableau    tab = irk->tableau;
694     TSIRKType irktype;
695     char          buf[512];
696 
697     ierr = TSIRKGetType(ts,&irktype);CHKERRQ(ierr);
698     ierr = PetscViewerASCIIPrintf(viewer,"  IRK type %s\n",irktype);CHKERRQ(ierr);
699     ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",irk->nstages,tab->c);CHKERRQ(ierr);
700     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa       c = %s\n",buf);CHKERRQ(ierr);
701     ierr = PetscViewerASCIIPrintf(viewer,"Stiffly accurate: %s\n",irk->stiffly_accurate ? "yes" : "no");CHKERRQ(ierr);
702     ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",PetscSqr(irk->nstages),tab->A);CHKERRQ(ierr);
703     ierr = PetscViewerASCIIPrintf(viewer,"  A coefficients       A = %s\n",buf);CHKERRQ(ierr);
704   }
705   PetscFunctionReturn(0);
706 }
707 
708 static PetscErrorCode TSLoad_IRK(TS ts,PetscViewer viewer)
709 {
710   PetscErrorCode ierr;
711   SNES           snes;
712   TSAdapt        adapt;
713 
714   PetscFunctionBegin;
715   ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
716   ierr = TSAdaptLoad(adapt,viewer);CHKERRQ(ierr);
717   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
718   ierr = SNESLoad(snes,viewer);CHKERRQ(ierr);
719   /* function and Jacobian context for SNES when used with TS is always ts object */
720   ierr = SNESSetFunction(snes,NULL,NULL,ts);CHKERRQ(ierr);
721   ierr = SNESSetJacobian(snes,NULL,NULL,NULL,ts);CHKERRQ(ierr);
722   PetscFunctionReturn(0);
723 }
724 
725 /*@C
726   TSIRKSetType - Set the type of IRK scheme
727 
728   Logically collective
729 
730   Input Parameters:
731 +  ts - timestepping context
732 -  irktype - type of IRK scheme
733 
734   Options Database:
735 .  -ts_irk_type <gauss> - set irk type
736 
737   Level: intermediate
738 
739 .seealso: TSIRKGetType(), TSIRK, TSIRKType, TSIRKGAUSS
740 @*/
741 PetscErrorCode TSIRKSetType(TS ts,TSIRKType irktype)
742 {
743   PetscErrorCode ierr;
744 
745   PetscFunctionBegin;
746   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
747   PetscValidCharPointer(irktype,2);
748   ierr = PetscTryMethod(ts,"TSIRKSetType_C",(TS,TSIRKType),(ts,irktype));CHKERRQ(ierr);
749   PetscFunctionReturn(0);
750 }
751 
752 /*@C
753   TSIRKGetType - Get the type of IRK IMEX scheme
754 
755   Logically collective
756 
757   Input Parameter:
758 .  ts - timestepping context
759 
760   Output Parameter:
761 .  irktype - type of IRK-IMEX scheme
762 
763   Level: intermediate
764 
765 .seealso: TSIRKGetType()
766 @*/
767 PetscErrorCode TSIRKGetType(TS ts,TSIRKType *irktype)
768 {
769   PetscErrorCode ierr;
770 
771   PetscFunctionBegin;
772   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
773   ierr = PetscUseMethod(ts,"TSIRKGetType_C",(TS,TSIRKType*),(ts,irktype));CHKERRQ(ierr);
774   PetscFunctionReturn(0);
775 }
776 
777 /*@C
778   TSIRKSetNumStages - Set the number of stages of IRK scheme
779 
780   Logically collective
781 
782   Input Parameters:
783 +  ts - timestepping context
784 -  nstages - number of stages of IRK scheme
785 
786   Options Database:
787 .  -ts_irk_nstages <int> - set number of stages
788 
789   Level: intermediate
790 
791 .seealso: TSIRKGetNumStages(), TSIRK
792 @*/
793 PetscErrorCode TSIRKSetNumStages(TS ts,PetscInt nstages)
794 {
795   PetscErrorCode ierr;
796 
797   PetscFunctionBegin;
798   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
799   ierr = PetscTryMethod(ts,"TSIRKSetNumStages_C",(TS,PetscInt),(ts,nstages));CHKERRQ(ierr);
800   PetscFunctionReturn(0);
801 }
802 
803 /*@C
804   TSIRKGetNumStages - Get the number of stages of IRK scheme
805 
806   Logically collective
807 
808   Input Parameters:
809 +  ts - timestepping context
810 -  nstages - number of stages of IRK scheme
811 
812   Level: intermediate
813 
814 .seealso: TSIRKSetNumStages(), TSIRK
815 @*/
816 PetscErrorCode TSIRKGetNumStages(TS ts,PetscInt *nstages)
817 {
818   PetscErrorCode ierr;
819 
820   PetscFunctionBegin;
821   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
822   PetscValidIntPointer(nstages,2);
823   ierr = PetscTryMethod(ts,"TSIRKGetNumStages_C",(TS,PetscInt*),(ts,nstages));CHKERRQ(ierr);
824   PetscFunctionReturn(0);
825 }
826 
827 static PetscErrorCode TSIRKGetType_IRK(TS ts,TSIRKType *irktype)
828 {
829   TS_IRK *irk = (TS_IRK*)ts->data;
830 
831   PetscFunctionBegin;
832   *irktype = irk->method_name;
833   PetscFunctionReturn(0);
834 }
835 
836 static PetscErrorCode TSIRKSetType_IRK(TS ts,TSIRKType irktype)
837 {
838   TS_IRK         *irk = (TS_IRK*)ts->data;
839   PetscErrorCode ierr,(*irkcreate)(TS);
840 
841   PetscFunctionBegin;
842   if (irk->method_name) {
843     ierr = PetscFree(irk->method_name);CHKERRQ(ierr);
844     ierr = TSIRKTableauReset(ts);CHKERRQ(ierr);
845   }
846   ierr = PetscFunctionListFind(TSIRKList,irktype,&irkcreate);CHKERRQ(ierr);
847   PetscCheckFalse(!irkcreate,PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSIRK type \"%s\" given",irktype);
848   ierr = (*irkcreate)(ts);CHKERRQ(ierr);
849   ierr = PetscStrallocpy(irktype,&irk->method_name);CHKERRQ(ierr);
850   PetscFunctionReturn(0);
851 }
852 
853 static PetscErrorCode TSIRKSetNumStages_IRK(TS ts,PetscInt nstages)
854 {
855   TS_IRK *irk = (TS_IRK*)ts->data;
856 
857   PetscFunctionBegin;
858   PetscCheckFalse(nstages<=0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"input argument, %d, out of range",nstages);
859   irk->nstages = nstages;
860   PetscFunctionReturn(0);
861 }
862 
863 static PetscErrorCode TSIRKGetNumStages_IRK(TS ts,PetscInt *nstages)
864 {
865   TS_IRK *irk = (TS_IRK*)ts->data;
866 
867   PetscFunctionBegin;
868   PetscValidIntPointer(nstages,2);
869   *nstages = irk->nstages;
870   PetscFunctionReturn(0);
871 }
872 
873 static PetscErrorCode TSDestroy_IRK(TS ts)
874 {
875   PetscErrorCode ierr;
876 
877   PetscFunctionBegin;
878   ierr = TSReset_IRK(ts);CHKERRQ(ierr);
879   if (ts->dm) {
880     ierr = DMCoarsenHookRemove(ts->dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr);
881     ierr = DMSubDomainHookRemove(ts->dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr);
882   }
883   ierr = PetscFree(ts->data);CHKERRQ(ierr);
884   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",NULL);CHKERRQ(ierr);
885   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",NULL);CHKERRQ(ierr);
886   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",NULL);CHKERRQ(ierr);
887   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",NULL);CHKERRQ(ierr);
888   PetscFunctionReturn(0);
889 }
890 
891 /*MC
892       TSIRK - ODE and DAE solver using Implicit Runge-Kutta schemes
893 
894   Notes:
895 
896   TSIRK uses the sparse Kronecker product matrix implementation of MATKAIJ to achieve good arithmetic intensity.
897 
898   Gauss-Legrendre methods are currently supported. These are A-stable symplectic methods with an arbitrary number of stages. The order of accuracy is 2s when using s stages. The default method uses three stages and thus has an order of six. The number of stages (thus order) can be set with -ts_irk_nstages or TSIRKSetNumStages().
899 
900   Level: beginner
901 
902 .seealso:  TSCreate(), TS, TSSetType(), TSIRKSetType(), TSIRKGetType(), TSIRKGAUSS, TSIRKRegister(), TSIRKSetNumStages()
903 
904 M*/
905 PETSC_EXTERN PetscErrorCode TSCreate_IRK(TS ts)
906 {
907   TS_IRK         *irk;
908   PetscErrorCode ierr;
909 
910   PetscFunctionBegin;
911   ierr = TSIRKInitializePackage();CHKERRQ(ierr);
912 
913   ts->ops->reset          = TSReset_IRK;
914   ts->ops->destroy        = TSDestroy_IRK;
915   ts->ops->view           = TSView_IRK;
916   ts->ops->load           = TSLoad_IRK;
917   ts->ops->setup          = TSSetUp_IRK;
918   ts->ops->step           = TSStep_IRK;
919   ts->ops->interpolate    = TSInterpolate_IRK;
920   ts->ops->evaluatestep   = TSEvaluateStep_IRK;
921   ts->ops->rollback       = TSRollBack_IRK;
922   ts->ops->setfromoptions = TSSetFromOptions_IRK;
923   ts->ops->snesfunction   = SNESTSFormFunction_IRK;
924   ts->ops->snesjacobian   = SNESTSFormJacobian_IRK;
925 
926   ts->usessnes = PETSC_TRUE;
927 
928   ierr = PetscNewLog(ts,&irk);CHKERRQ(ierr);
929   ts->data = (void*)irk;
930 
931   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",TSIRKSetType_IRK);CHKERRQ(ierr);
932   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",TSIRKGetType_IRK);CHKERRQ(ierr);
933   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",TSIRKSetNumStages_IRK);CHKERRQ(ierr);
934   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",TSIRKGetNumStages_IRK);CHKERRQ(ierr);
935   /* 3-stage IRK_Gauss is the default */
936   ierr = PetscNew(&irk->tableau);CHKERRQ(ierr);
937   irk->nstages = 3;
938   ierr = TSIRKSetType(ts,TSIRKDefault);CHKERRQ(ierr);
939   PetscFunctionReturn(0);
940 }
941