xref: /petsc/src/ts/impls/implicit/irk/irk.c (revision 2fa40bb9206b96114faa7cb222621ec184d31cd2)
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 = PetscInfo2(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   if (!B) SETERRQ1(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
559     SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,"TSIRK %s does not support implicit formula",irk->method_name); /* ToDo: need the mass matrix for DAE  */
560   ts->dm = dmsave;
561   PetscFunctionReturn(0);
562 }
563 
564 static PetscErrorCode DMCoarsenHook_TSIRK(DM fine,DM coarse,void *ctx)
565 {
566   PetscFunctionBegin;
567   PetscFunctionReturn(0);
568 }
569 
570 static PetscErrorCode DMRestrictHook_TSIRK(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
571 {
572   TS             ts = (TS)ctx;
573   Vec            U,U_c;
574   PetscErrorCode ierr;
575 
576   PetscFunctionBegin;
577   ierr = TSIRKGetVecs(ts,fine,&U);CHKERRQ(ierr);
578   ierr = TSIRKGetVecs(ts,coarse,&U_c);CHKERRQ(ierr);
579   ierr = MatRestrict(restrct,U,U_c);CHKERRQ(ierr);
580   ierr = VecPointwiseMult(U_c,rscale,U_c);CHKERRQ(ierr);
581   ierr = TSIRKRestoreVecs(ts,fine,&U);CHKERRQ(ierr);
582   ierr = TSIRKRestoreVecs(ts,coarse,&U_c);CHKERRQ(ierr);
583   PetscFunctionReturn(0);
584 }
585 
586 static PetscErrorCode DMSubDomainHook_TSIRK(DM dm,DM subdm,void *ctx)
587 {
588   PetscFunctionBegin;
589   PetscFunctionReturn(0);
590 }
591 
592 static PetscErrorCode DMSubDomainRestrictHook_TSIRK(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
593 {
594   TS             ts = (TS)ctx;
595   Vec            U,U_c;
596   PetscErrorCode ierr;
597 
598   PetscFunctionBegin;
599   ierr = TSIRKGetVecs(ts,dm,&U);CHKERRQ(ierr);
600   ierr = TSIRKGetVecs(ts,subdm,&U_c);CHKERRQ(ierr);
601 
602   ierr = VecScatterBegin(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
603   ierr = VecScatterEnd(gscat,U,U_c,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
604 
605   ierr = TSIRKRestoreVecs(ts,dm,&U);CHKERRQ(ierr);
606   ierr = TSIRKRestoreVecs(ts,subdm,&U_c);CHKERRQ(ierr);
607   PetscFunctionReturn(0);
608 }
609 
610 static PetscErrorCode TSSetUp_IRK(TS ts)
611 {
612   TS_IRK         *irk = (TS_IRK*)ts->data;
613   IRKTableau     tab = irk->tableau;
614   DM             dm;
615   Mat            J;
616   Vec            R;
617   const PetscInt nstages = irk->nstages;
618   PetscInt       vsize,bs;
619   PetscErrorCode ierr;
620 
621   PetscFunctionBegin;
622   if (!irk->work) {
623     ierr = PetscMalloc1(irk->nstages,&irk->work);CHKERRQ(ierr);
624   }
625   if (!irk->Y) {
626     ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->Y);CHKERRQ(ierr);
627   }
628   if (!irk->YdotI) {
629     ierr = VecDuplicateVecs(ts->vec_sol,irk->nstages,&irk->YdotI);CHKERRQ(ierr);
630   }
631   if (!irk->Ydot) {
632     ierr = VecDuplicate(ts->vec_sol,&irk->Ydot);CHKERRQ(ierr);
633   }
634   if (!irk->U) {
635     ierr = VecDuplicate(ts->vec_sol,&irk->U);CHKERRQ(ierr);
636   }
637   if (!irk->U0) {
638     ierr = VecDuplicate(ts->vec_sol,&irk->U0);CHKERRQ(ierr);
639   }
640   if (!irk->Z) {
641     ierr = VecCreate(PetscObjectComm((PetscObject)ts->vec_sol),&irk->Z);CHKERRQ(ierr);
642     ierr = VecGetSize(ts->vec_sol,&vsize);CHKERRQ(ierr);
643     ierr = VecSetSizes(irk->Z,PETSC_DECIDE,vsize*irk->nstages);CHKERRQ(ierr);
644     ierr = VecGetBlockSize(ts->vec_sol,&bs);CHKERRQ(ierr);
645     ierr = VecSetBlockSize(irk->Z,irk->nstages*bs);CHKERRQ(ierr);
646     ierr = VecSetFromOptions(irk->Z);CHKERRQ(ierr);
647   }
648   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
649   ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr);
650   ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr);
651 
652   ierr = TSGetSNES(ts,&ts->snes);CHKERRQ(ierr);
653   ierr = VecDuplicate(irk->Z,&R);CHKERRQ(ierr);
654   ierr = SNESSetFunction(ts->snes,R,SNESTSFormFunction,ts);CHKERRQ(ierr);
655   ierr = SNESGetJacobian(ts->snes,&J,NULL,NULL,NULL);CHKERRQ(ierr);
656   if (!irk->TJ) {
657     /* Create the KAIJ matrix for solving the stages */
658     ierr = MatCreateKAIJ(J,nstages,nstages,tab->A_inv,tab->I_s,&irk->TJ);CHKERRQ(ierr);
659   }
660   ierr = SNESSetJacobian(ts->snes,irk->TJ,irk->TJ,SNESTSFormJacobian,ts);CHKERRQ(ierr);
661   ierr = VecDestroy(&R);CHKERRQ(ierr);
662   PetscFunctionReturn(0);
663 }
664 
665 static PetscErrorCode TSSetFromOptions_IRK(PetscOptionItems *PetscOptionsObject,TS ts)
666 {
667   TS_IRK         *irk = (TS_IRK*)ts->data;
668   char           tname[256] = TSIRKGAUSS;
669   PetscErrorCode ierr;
670 
671   PetscFunctionBegin;
672   ierr = PetscOptionsHead(PetscOptionsObject,"IRK ODE solver options");CHKERRQ(ierr);
673   {
674     PetscBool flg1,flg2;
675     ierr = PetscOptionsInt("-ts_irk_nstages","Stages of the IRK method","TSIRKSetNumStages",irk->nstages,&irk->nstages,&flg1);CHKERRQ(ierr);
676     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);
677     if (flg1 ||flg2 || !irk->method_name[0]) { /* Create the method tableau after nstages or method is set */
678       ierr = TSIRKSetType(ts,tname);CHKERRQ(ierr);
679     }
680   }
681   ierr = PetscOptionsTail();CHKERRQ(ierr);
682   PetscFunctionReturn(0);
683 }
684 
685 static PetscErrorCode TSView_IRK(TS ts,PetscViewer viewer)
686 {
687   TS_IRK         *irk = (TS_IRK*)ts->data;
688   PetscBool      iascii;
689   PetscErrorCode ierr;
690 
691   PetscFunctionBegin;
692   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
693   if (iascii) {
694     IRKTableau    tab = irk->tableau;
695     TSIRKType irktype;
696     char          buf[512];
697 
698     ierr = TSIRKGetType(ts,&irktype);CHKERRQ(ierr);
699     ierr = PetscViewerASCIIPrintf(viewer,"  IRK type %s\n",irktype);CHKERRQ(ierr);
700     ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",irk->nstages,tab->c);CHKERRQ(ierr);
701     ierr = PetscViewerASCIIPrintf(viewer,"  Abscissa       c = %s\n",buf);CHKERRQ(ierr);
702     ierr = PetscViewerASCIIPrintf(viewer,"Stiffly accurate: %s\n",irk->stiffly_accurate ? "yes" : "no");CHKERRQ(ierr);
703     ierr = PetscFormatRealArray(buf,sizeof(buf),"% 8.6f",PetscSqr(irk->nstages),tab->A);CHKERRQ(ierr);
704     ierr = PetscViewerASCIIPrintf(viewer,"  A coefficients       A = %s\n",buf);CHKERRQ(ierr);
705   }
706   PetscFunctionReturn(0);
707 }
708 
709 static PetscErrorCode TSLoad_IRK(TS ts,PetscViewer viewer)
710 {
711   PetscErrorCode ierr;
712   SNES           snes;
713   TSAdapt        adapt;
714 
715   PetscFunctionBegin;
716   ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
717   ierr = TSAdaptLoad(adapt,viewer);CHKERRQ(ierr);
718   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
719   ierr = SNESLoad(snes,viewer);CHKERRQ(ierr);
720   /* function and Jacobian context for SNES when used with TS is always ts object */
721   ierr = SNESSetFunction(snes,NULL,NULL,ts);CHKERRQ(ierr);
722   ierr = SNESSetJacobian(snes,NULL,NULL,NULL,ts);CHKERRQ(ierr);
723   PetscFunctionReturn(0);
724 }
725 
726 /*@C
727   TSIRKSetType - Set the type of IRK scheme
728 
729   Logically collective
730 
731   Input Parameters:
732 +  ts - timestepping context
733 -  irktype - type of IRK scheme
734 
735   Options Database:
736 .  -ts_irk_type <gauss>
737 
738   Level: intermediate
739 
740 .seealso: TSIRKGetType(), TSIRK, TSIRKType, TSIRKGAUSS
741 @*/
742 PetscErrorCode TSIRKSetType(TS ts,TSIRKType irktype)
743 {
744   PetscErrorCode ierr;
745 
746   PetscFunctionBegin;
747   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
748   PetscValidCharPointer(irktype,2);
749   ierr = PetscTryMethod(ts,"TSIRKSetType_C",(TS,TSIRKType),(ts,irktype));CHKERRQ(ierr);
750   PetscFunctionReturn(0);
751 }
752 
753 /*@C
754   TSIRKGetType - Get the type of IRK IMEX scheme
755 
756   Logically collective
757 
758   Input Parameter:
759 .  ts - timestepping context
760 
761   Output Parameter:
762 .  irktype - type of IRK-IMEX scheme
763 
764   Level: intermediate
765 
766 .seealso: TSIRKGetType()
767 @*/
768 PetscErrorCode TSIRKGetType(TS ts,TSIRKType *irktype)
769 {
770   PetscErrorCode ierr;
771 
772   PetscFunctionBegin;
773   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
774   ierr = PetscUseMethod(ts,"TSIRKGetType_C",(TS,TSIRKType*),(ts,irktype));CHKERRQ(ierr);
775   PetscFunctionReturn(0);
776 }
777 
778 /*@C
779   TSIRKSetNumStages - Set the number of stages of IRK scheme
780 
781   Logically collective
782 
783   Input Parameters:
784 +  ts - timestepping context
785 -  nstages - number of stages of IRK scheme
786 
787   Options Database:
788 .  -ts_irk_nstages <int>: Number of stages
789 
790   Level: intermediate
791 
792 .seealso: TSIRKGetNumStages(), TSIRK
793 @*/
794 PetscErrorCode TSIRKSetNumStages(TS ts,PetscInt nstages)
795 {
796   PetscErrorCode ierr;
797 
798   PetscFunctionBegin;
799   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
800   ierr = PetscTryMethod(ts,"TSIRKSetNumStages_C",(TS,PetscInt),(ts,nstages));CHKERRQ(ierr);
801   PetscFunctionReturn(0);
802 }
803 
804 /*@C
805   TSIRKGetNumStages - Get the number of stages of IRK scheme
806 
807   Logically collective
808 
809   Input Parameters:
810 +  ts - timestepping context
811 -  nstages - number of stages of IRK scheme
812 
813   Level: intermediate
814 
815 .seealso: TSIRKSetNumStages(), TSIRK
816 @*/
817 PetscErrorCode TSIRKGetNumStages(TS ts,PetscInt *nstages)
818 {
819   PetscErrorCode ierr;
820 
821   PetscFunctionBegin;
822   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
823   PetscValidIntPointer(nstages,2);
824   ierr = PetscTryMethod(ts,"TSIRKGetNumStages_C",(TS,PetscInt*),(ts,nstages));CHKERRQ(ierr);
825   PetscFunctionReturn(0);
826 }
827 
828 static PetscErrorCode TSIRKGetType_IRK(TS ts,TSIRKType *irktype)
829 {
830   TS_IRK *irk = (TS_IRK*)ts->data;
831 
832   PetscFunctionBegin;
833   *irktype = irk->method_name;
834   PetscFunctionReturn(0);
835 }
836 
837 static PetscErrorCode TSIRKSetType_IRK(TS ts,TSIRKType irktype)
838 {
839   TS_IRK         *irk = (TS_IRK*)ts->data;
840   PetscErrorCode ierr,(*irkcreate)(TS);
841 
842   PetscFunctionBegin;
843   if (irk->method_name) {
844     ierr = PetscFree(irk->method_name);CHKERRQ(ierr);
845     ierr = TSIRKTableauReset(ts);CHKERRQ(ierr);
846   }
847   ierr = PetscFunctionListFind(TSIRKList,irktype,&irkcreate);CHKERRQ(ierr);
848   if (!irkcreate) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSIRK type \"%s\" given",irktype);
849   ierr = (*irkcreate)(ts);CHKERRQ(ierr);
850   ierr = PetscStrallocpy(irktype,&irk->method_name);CHKERRQ(ierr);
851   PetscFunctionReturn(0);
852 }
853 
854 static PetscErrorCode TSIRKSetNumStages_IRK(TS ts,PetscInt nstages)
855 {
856   TS_IRK *irk = (TS_IRK*)ts->data;
857 
858   PetscFunctionBegin;
859   if (nstages<=0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"input argument, %d, out of range",nstages);
860   irk->nstages = nstages;
861   PetscFunctionReturn(0);
862 }
863 
864 static PetscErrorCode TSIRKGetNumStages_IRK(TS ts,PetscInt *nstages)
865 {
866   TS_IRK *irk = (TS_IRK*)ts->data;
867 
868   PetscFunctionBegin;
869   PetscValidIntPointer(nstages,2);
870   *nstages = irk->nstages;
871   PetscFunctionReturn(0);
872 }
873 
874 static PetscErrorCode TSDestroy_IRK(TS ts)
875 {
876   PetscErrorCode ierr;
877 
878   PetscFunctionBegin;
879   ierr = TSReset_IRK(ts);CHKERRQ(ierr);
880   if (ts->dm) {
881     ierr = DMCoarsenHookRemove(ts->dm,DMCoarsenHook_TSIRK,DMRestrictHook_TSIRK,ts);CHKERRQ(ierr);
882     ierr = DMSubDomainHookRemove(ts->dm,DMSubDomainHook_TSIRK,DMSubDomainRestrictHook_TSIRK,ts);CHKERRQ(ierr);
883   }
884   ierr = PetscFree(ts->data);CHKERRQ(ierr);
885   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",NULL);CHKERRQ(ierr);
886   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",NULL);CHKERRQ(ierr);
887   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",NULL);CHKERRQ(ierr);
888   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",NULL);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 /*MC
893       TSIRK - ODE and DAE solver using Implicit Runge-Kutta schemes
894 
895   Notes:
896 
897   TSIRK uses the sparse Kronecker product matrix implementation of MATKAIJ to achieve good arithmetic intensity.
898 
899   The default is TSIRK3, it can be changed with TSIRKSetType() or -ts_irk_type
900 
901   If the equation is implicit or a DAE, then TSSetEquationType() needs to be set accordingly. Refer to the manual for further information.
902 
903   Consider trying TSROSW if the stiff part is linear or weakly nonlinear.
904 
905   Level: beginner
906 
907 .seealso:  TSCreate(), TS, TSSetType(), TSIRKSetType(), TSIRKGetType(),
908            TSIRK1BEE, TSIRK2C, TSIRK2D, TSIRK2E, TSIRK3, TSIRKL2, TSIRKA2, TSIRKARS122,
909            TSIRK4, TSIRK5, TSIRKPRSSP2, TSIRKARS443, TSIRKBPR3, TSIRKType, TSIRKRegister()
910 
911 M*/
912 PETSC_EXTERN PetscErrorCode TSCreate_IRK(TS ts)
913 {
914   TS_IRK         *irk;
915   PetscErrorCode ierr;
916 
917   PetscFunctionBegin;
918   ierr = TSIRKInitializePackage();CHKERRQ(ierr);
919 
920   ts->ops->reset          = TSReset_IRK;
921   ts->ops->destroy        = TSDestroy_IRK;
922   ts->ops->view           = TSView_IRK;
923   ts->ops->load           = TSLoad_IRK;
924   ts->ops->setup          = TSSetUp_IRK;
925   ts->ops->step           = TSStep_IRK;
926   ts->ops->interpolate    = TSInterpolate_IRK;
927   ts->ops->evaluatestep   = TSEvaluateStep_IRK;
928   ts->ops->rollback       = TSRollBack_IRK;
929   ts->ops->setfromoptions = TSSetFromOptions_IRK;
930   ts->ops->snesfunction   = SNESTSFormFunction_IRK;
931   ts->ops->snesjacobian   = SNESTSFormJacobian_IRK;
932 
933   ts->usessnes = PETSC_TRUE;
934 
935   ierr = PetscNewLog(ts,&irk);CHKERRQ(ierr);
936   ts->data = (void*)irk;
937 
938   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetType_C",TSIRKSetType_IRK);CHKERRQ(ierr);
939   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetType_C",TSIRKGetType_IRK);CHKERRQ(ierr);
940   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKSetNumStages_C",TSIRKSetNumStages_IRK);CHKERRQ(ierr);
941   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSIRKGetNumStages_C",TSIRKGetNumStages_IRK);CHKERRQ(ierr);
942   /* 3-stage IRK_Gauss is the default */
943   ierr = PetscNew(&irk->tableau);CHKERRQ(ierr);
944   irk->nstages = 3;
945   ierr = TSIRKSetType(ts,TSIRKDefault);CHKERRQ(ierr);
946   PetscFunctionReturn(0);
947 }
948