xref: /petsc/src/ts/impls/implicit/sundials/sundials.c (revision df4cd43f92eaa320656440c40edb1046daee8f75)
1 /*
2     Provides a PETSc interface to version 2.5 of SUNDIALS/CVODE solver (a very old version)
3     The interface to PVODE (old version of CVODE) was originally contributed
4     by Liyang Xu. It has been redone by Hong Zhang and Dinesh Kaushik.
5 
6     Reference: sundials-2.4.0/examples/cvode/parallel/cvDiurnal_kry_p.c
7 */
8 #include <../src/ts/impls/implicit/sundials/sundials.h> /*I "petscts.h" I*/
9 
10 /*
11       TSPrecond_Sundials - function that we provide to SUNDIALS to
12                         evaluate the preconditioner.
13 */
14 static PetscErrorCode TSPrecond_Sundials_Petsc(realtype tn, N_Vector y, N_Vector fy, booleantype jok, booleantype *jcurPtr, realtype _gamma, void *P_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
15 {
16   TS           ts    = (TS)P_data;
17   TS_Sundials *cvode = (TS_Sundials *)ts->data;
18   PC           pc;
19   Mat          J, P;
20   Vec          yy = cvode->w1, yydot = cvode->ydot;
21   PetscReal    gm = (PetscReal)_gamma;
22   PetscScalar *y_data;
23 
24   PetscFunctionBegin;
25   PetscCall(TSGetIJacobian(ts, &J, &P, NULL, NULL));
26   y_data = (PetscScalar *)N_VGetArrayPointer(y);
27   PetscCall(VecPlaceArray(yy, y_data));
28   PetscCall(VecZeroEntries(yydot)); /* The Jacobian is independent of Ydot for ODE which is all that CVode works for */
29   /* compute the shifted Jacobian   (1/gm)*I + Jrest */
30   PetscCall(TSComputeIJacobian(ts, ts->ptime, yy, yydot, 1 / gm, J, P, PETSC_FALSE));
31   PetscCall(VecResetArray(yy));
32   PetscCall(MatScale(P, gm)); /* turn into I-gm*Jrest, J is not used by SUNDIALS  */
33   *jcurPtr = TRUE;
34   PetscCall(TSSundialsGetPC(ts, &pc));
35   PetscCall(PCSetOperators(pc, J, P));
36   PetscFunctionReturn(PETSC_SUCCESS);
37 }
38 
39 /* Sundial expects an int (*)(args...) but PetscErrorCode is an enum. Instead of switching out
40    all the PetscCalls in TSPrecond_Sundials_Petsc we just wrap it */
41 static int TSPrecond_Sundials_Private(realtype tn, N_Vector y, N_Vector fy, booleantype jok, booleantype *jcurPtr, realtype _gamma, void *P_data, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
42 {
43   return (int)TSPrecond_Sundials_Petsc(tn, y, fy, jok, jcurPtr, _gamma, P_data, vtemp1, vtemp2, vtemp3);
44 }
45 
46 /*
47      TSPSolve_Sundials -  routine that we provide to SUNDIALS that applies the preconditioner.
48 */
49 static PetscErrorCode TSPSolve_Sundials_Petsc(realtype tn, N_Vector y, N_Vector fy, N_Vector r, N_Vector z, realtype _gamma, realtype delta, int lr, void *P_data, N_Vector vtemp)
50 {
51   TS           ts    = (TS)P_data;
52   TS_Sundials *cvode = (TS_Sundials *)ts->data;
53   PC           pc;
54   Vec          rr = cvode->w1, zz = cvode->w2;
55   PetscScalar *r_data, *z_data;
56 
57   PetscFunctionBegin;
58   /* Make the PETSc work vectors rr and zz point to the arrays in the SUNDIALS vectors r and z respectively*/
59   r_data = (PetscScalar *)N_VGetArrayPointer(r);
60   z_data = (PetscScalar *)N_VGetArrayPointer(z);
61   PetscCall(VecPlaceArray(rr, r_data));
62   PetscCall(VecPlaceArray(zz, z_data));
63 
64   /* Solve the Px=r and put the result in zz */
65   PetscCall(TSSundialsGetPC(ts, &pc));
66   PetscCall(PCApply(pc, rr, zz));
67   PetscCall(VecResetArray(rr));
68   PetscCall(VecResetArray(zz));
69   PetscFunctionReturn(PETSC_SUCCESS);
70 }
71 
72 /* See TSPrecond_Sundials_Private() */
73 static int TSPSolve_Sundials_Private(realtype tn, N_Vector y, N_Vector fy, N_Vector r, N_Vector z, realtype _gamma, realtype delta, int lr, void *P_data, N_Vector vtemp)
74 {
75   return (int)TSPSolve_Sundials_Petsc(tn, y, fy, r, z, _gamma, delta, lr, P_data, vtemp);
76 }
77 
78 /*
79         TSFunction_Sundials - routine that we provide to SUNDIALS that applies the right hand side.
80 */
81 int TSFunction_Sundials(realtype t, N_Vector y, N_Vector ydot, void *ctx)
82 {
83   TS           ts = (TS)ctx;
84   DM           dm;
85   DMTS         tsdm;
86   TSIFunction  ifunction;
87   MPI_Comm     comm;
88   TS_Sundials *cvode = (TS_Sundials *)ts->data;
89   Vec          yy = cvode->w1, yyd = cvode->w2, yydot = cvode->ydot;
90   PetscScalar *y_data, *ydot_data;
91 
92   PetscFunctionBegin;
93   PetscCall(PetscObjectGetComm((PetscObject)ts, &comm));
94   /* Make the PETSc work vectors yy and yyd point to the arrays in the SUNDIALS vectors y and ydot respectively*/
95   y_data    = (PetscScalar *)N_VGetArrayPointer(y);
96   ydot_data = (PetscScalar *)N_VGetArrayPointer(ydot);
97   PetscCallAbort(comm, VecPlaceArray(yy, y_data));
98   PetscCallAbort(comm, VecPlaceArray(yyd, ydot_data));
99 
100   /* Now compute the right hand side function, via IFunction unless only the more efficient RHSFunction is set */
101   PetscCall(TSGetDM(ts, &dm));
102   PetscCall(DMGetDMTS(dm, &tsdm));
103   PetscCall(DMTSGetIFunction(dm, &ifunction, NULL));
104   if (!ifunction) {
105     PetscCall(TSComputeRHSFunction(ts, t, yy, yyd));
106   } else { /* If rhsfunction is also set, this computes both parts and shifts them to the right */
107     PetscCall(VecZeroEntries(yydot));
108     PetscCallAbort(comm, TSComputeIFunction(ts, t, yy, yydot, yyd, PETSC_FALSE));
109     PetscCall(VecScale(yyd, -1.));
110   }
111   PetscCallAbort(comm, VecResetArray(yy));
112   PetscCallAbort(comm, VecResetArray(yyd));
113   PetscFunctionReturn(PETSC_SUCCESS);
114 }
115 
116 /*
117        TSStep_Sundials - Calls SUNDIALS to integrate the ODE.
118 */
119 PetscErrorCode TSStep_Sundials(TS ts)
120 {
121   TS_Sundials *cvode = (TS_Sundials *)ts->data;
122   PetscInt     flag;
123   long int     nits, lits, nsteps;
124   realtype     t, tout;
125   PetscScalar *y_data;
126   void        *mem;
127 
128   PetscFunctionBegin;
129   mem  = cvode->mem;
130   tout = ts->max_time;
131   PetscCall(VecGetArray(ts->vec_sol, &y_data));
132   N_VSetArrayPointer((realtype *)y_data, cvode->y);
133   PetscCall(VecRestoreArray(ts->vec_sol, NULL));
134 
135   /* We would like to TSPreStage() and TSPostStage()
136    * before each stage solve but CVode does not appear to support this. */
137   if (cvode->monitorstep) flag = CVode(mem, tout, cvode->y, &t, CV_ONE_STEP);
138   else flag = CVode(mem, tout, cvode->y, &t, CV_NORMAL);
139 
140   if (flag) { /* display error message */
141     switch (flag) {
142     case CV_ILL_INPUT:
143       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_ILL_INPUT");
144       break;
145     case CV_TOO_CLOSE:
146       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_TOO_CLOSE");
147       break;
148     case CV_TOO_MUCH_WORK: {
149       PetscReal tcur;
150       PetscCallExternal(CVodeGetNumSteps, mem, &nsteps);
151       PetscCallExternal(CVodeGetCurrentTime, mem, &tcur);
152       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_TOO_MUCH_WORK. At t=%g, nsteps %ld exceeds maxstep %" PetscInt_FMT ". Increase '-ts_max_steps <>' or modify TSSetMaxSteps()", (double)tcur, nsteps, ts->max_steps);
153     } break;
154     case CV_TOO_MUCH_ACC:
155       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_TOO_MUCH_ACC");
156       break;
157     case CV_ERR_FAILURE:
158       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_ERR_FAILURE");
159       break;
160     case CV_CONV_FAILURE:
161       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_CONV_FAILURE");
162       break;
163     case CV_LINIT_FAIL:
164       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_LINIT_FAIL");
165       break;
166     case CV_LSETUP_FAIL:
167       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_LSETUP_FAIL");
168       break;
169     case CV_LSOLVE_FAIL:
170       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_LSOLVE_FAIL");
171       break;
172     case CV_RHSFUNC_FAIL:
173       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_RHSFUNC_FAIL");
174       break;
175     case CV_FIRST_RHSFUNC_ERR:
176       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_FIRST_RHSFUNC_ERR");
177       break;
178     case CV_REPTD_RHSFUNC_ERR:
179       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_REPTD_RHSFUNC_ERR");
180       break;
181     case CV_UNREC_RHSFUNC_ERR:
182       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_UNREC_RHSFUNC_ERR");
183       break;
184     case CV_RTFUNC_FAIL:
185       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, CV_RTFUNC_FAIL");
186       break;
187     default:
188       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "CVode() fails, flag %d", flag);
189     }
190   }
191 
192   /* log inner nonlinear and linear iterations */
193   PetscCallExternal(CVodeGetNumNonlinSolvIters, mem, &nits);
194   PetscCallExternal(CVSpilsGetNumLinIters, mem, &lits);
195   ts->snes_its += nits;
196   ts->ksp_its = lits;
197 
198   /* copy the solution from cvode->y to cvode->update and sol */
199   PetscCall(VecPlaceArray(cvode->w1, y_data));
200   PetscCall(VecCopy(cvode->w1, cvode->update));
201   PetscCall(VecResetArray(cvode->w1));
202   PetscCall(VecCopy(cvode->update, ts->vec_sol));
203 
204   ts->time_step = t - ts->ptime;
205   ts->ptime     = t;
206 
207   PetscCallExternal(CVodeGetNumSteps, mem, &nsteps);
208   if (!cvode->monitorstep) ts->steps += nsteps - 1; /* TSStep() increments the step counter by one */
209   PetscFunctionReturn(PETSC_SUCCESS);
210 }
211 
212 static PetscErrorCode TSInterpolate_Sundials(TS ts, PetscReal t, Vec X)
213 {
214   TS_Sundials *cvode = (TS_Sundials *)ts->data;
215   N_Vector     y;
216   PetscScalar *x_data;
217   PetscInt     glosize, locsize;
218 
219   PetscFunctionBegin;
220   /* get the vector size */
221   PetscCall(VecGetSize(X, &glosize));
222   PetscCall(VecGetLocalSize(X, &locsize));
223   PetscCall(VecGetArray(X, &x_data));
224 
225   /* Initialize N_Vec y with x_data */
226   if (cvode->use_dense) {
227     PetscMPIInt size;
228 
229     PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
230     PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "TSSUNDIALS only supports a dense solve in the serial case");
231     y = N_VMake_Serial(locsize, (realtype *)x_data);
232   } else {
233     y = N_VMake_Parallel(cvode->comm_sundials, locsize, glosize, (realtype *)x_data);
234   }
235 
236   PetscCheck(y, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Interpolated y is not allocated");
237 
238   PetscCallExternal(CVodeGetDky, cvode->mem, t, 0, y);
239   PetscCall(VecRestoreArray(X, &x_data));
240   PetscFunctionReturn(PETSC_SUCCESS);
241 }
242 
243 PetscErrorCode TSReset_Sundials(TS ts)
244 {
245   TS_Sundials *cvode = (TS_Sundials *)ts->data;
246 
247   PetscFunctionBegin;
248   PetscCall(VecDestroy(&cvode->update));
249   PetscCall(VecDestroy(&cvode->ydot));
250   PetscCall(VecDestroy(&cvode->w1));
251   PetscCall(VecDestroy(&cvode->w2));
252   if (cvode->mem) CVodeFree(&cvode->mem);
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 PetscErrorCode TSDestroy_Sundials(TS ts)
257 {
258   TS_Sundials *cvode = (TS_Sundials *)ts->data;
259 
260   PetscFunctionBegin;
261   PetscCall(TSReset_Sundials(ts));
262   PetscCallMPI(MPI_Comm_free(&(cvode->comm_sundials)));
263   PetscCall(PetscFree(ts->data));
264   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetType_C", NULL));
265   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMaxl_C", NULL));
266   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetLinearTolerance_C", NULL));
267   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetGramSchmidtType_C", NULL));
268   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetTolerance_C", NULL));
269   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMinTimeStep_C", NULL));
270   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMaxTimeStep_C", NULL));
271   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsGetPC_C", NULL));
272   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsGetIterations_C", NULL));
273   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsMonitorInternalSteps_C", NULL));
274   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetUseDense_C", NULL));
275   PetscFunctionReturn(PETSC_SUCCESS);
276 }
277 
278 PetscErrorCode TSSetUp_Sundials(TS ts)
279 {
280   TS_Sundials *cvode = (TS_Sundials *)ts->data;
281   PetscInt     glosize, locsize, i;
282   PetscScalar *y_data, *parray;
283   PC           pc;
284   PCType       pctype;
285   PetscBool    pcnone;
286 
287   PetscFunctionBegin;
288   PetscCheck(ts->exact_final_time != TS_EXACTFINALTIME_MATCHSTEP, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for exact final time option 'MATCHSTEP' when using SUNDIALS");
289 
290   /* get the vector size */
291   PetscCall(VecGetSize(ts->vec_sol, &glosize));
292   PetscCall(VecGetLocalSize(ts->vec_sol, &locsize));
293 
294   /* allocate the memory for N_Vec y */
295   if (cvode->use_dense) {
296     PetscMPIInt size;
297 
298     PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
299     PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "TSSUNDIALS only supports a dense solve in the serial case");
300     cvode->y = N_VNew_Serial(locsize);
301   } else {
302     cvode->y = N_VNew_Parallel(cvode->comm_sundials, locsize, glosize);
303   }
304   PetscCheck(cvode->y, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "cvode->y is not allocated");
305 
306   /* initialize N_Vec y: copy ts->vec_sol to cvode->y */
307   PetscCall(VecGetArray(ts->vec_sol, &parray));
308   y_data = (PetscScalar *)N_VGetArrayPointer(cvode->y);
309   for (i = 0; i < locsize; i++) y_data[i] = parray[i];
310   PetscCall(VecRestoreArray(ts->vec_sol, NULL));
311 
312   PetscCall(VecDuplicate(ts->vec_sol, &cvode->update));
313   PetscCall(VecDuplicate(ts->vec_sol, &cvode->ydot));
314 
315   /*
316     Create work vectors for the TSPSolve_Sundials() routine. Note these are
317     allocated with zero space arrays because the actual array space is provided
318     by SUNDIALS and set using VecPlaceArray().
319   */
320   PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)ts), 1, locsize, PETSC_DECIDE, NULL, &cvode->w1));
321   PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)ts), 1, locsize, PETSC_DECIDE, NULL, &cvode->w2));
322 
323   /* Call CVodeCreate to create the solver memory and the use of a Newton iteration */
324   cvode->mem = CVodeCreate(cvode->cvode_type, CV_NEWTON);
325   PetscCheck(cvode->mem, PETSC_COMM_SELF, PETSC_ERR_MEM, "CVodeCreate() fails");
326 
327   /* Set the pointer to user-defined data */
328   PetscCallExternal(CVodeSetUserData, cvode->mem, ts);
329 
330   /* SUNDIALS may choose to use a smaller initial step, but will never use a larger step. */
331   PetscCallExternal(CVodeSetInitStep, cvode->mem, (realtype)ts->time_step);
332   if (cvode->mindt > 0) {
333     int flag = CVodeSetMinStep(cvode->mem, (realtype)cvode->mindt);
334     if (flag) {
335       PetscCheck(flag != CV_MEM_NULL, PetscObjectComm((PetscObject)ts), PETSC_ERR_LIB, "CVodeSetMinStep() failed, cvode_mem pointer is NULL");
336       PetscCheck(flag != CV_ILL_INPUT, PetscObjectComm((PetscObject)ts), PETSC_ERR_LIB, "CVodeSetMinStep() failed, hmin is nonpositive or it exceeds the maximum allowable step size");
337       SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_LIB, "CVodeSetMinStep() failed");
338     }
339   }
340   if (cvode->maxdt > 0) PetscCallExternal(CVodeSetMaxStep, cvode->mem, (realtype)cvode->maxdt);
341 
342   /* Call CVodeInit to initialize the integrator memory and specify the
343    * user's right hand side function in u'=f(t,u), the initial time T0, and
344    * the initial dependent variable vector cvode->y */
345   PetscCallExternal(CVodeInit, cvode->mem, TSFunction_Sundials, ts->ptime, cvode->y);
346 
347   /* specifies scalar relative and absolute tolerances */
348   PetscCallExternal(CVodeSStolerances, cvode->mem, cvode->reltol, cvode->abstol);
349 
350   /* Specify max order of BDF / ADAMS method */
351   if (cvode->maxord != PETSC_DEFAULT) PetscCallExternal(CVodeSetMaxOrd, cvode->mem, cvode->maxord);
352 
353   /* Specify max num of steps to be taken by cvode in its attempt to reach the next output time */
354   PetscCallExternal(CVodeSetMaxNumSteps, cvode->mem, ts->max_steps);
355 
356   if (cvode->use_dense) {
357     PetscCallExternal(CVDense, cvode->mem, locsize);
358   } else {
359     /* call CVSpgmr to use GMRES as the linear solver.        */
360     /* setup the ode integrator with the given preconditioner */
361     PetscCall(TSSundialsGetPC(ts, &pc));
362     PetscCall(PCGetType(pc, &pctype));
363     PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCNONE, &pcnone));
364     if (pcnone) {
365       PetscCallExternal(CVSpgmr, cvode->mem, PREC_NONE, 0);
366     } else {
367       PetscCallExternal(CVSpgmr, cvode->mem, PREC_LEFT, cvode->maxl);
368 
369       /* Set preconditioner and solve routines Precond and PSolve,
370          and the pointer to the user-defined block data */
371       PetscCallExternal(CVSpilsSetPreconditioner, cvode->mem, TSPrecond_Sundials_Private, TSPSolve_Sundials_Private);
372     }
373   }
374   PetscFunctionReturn(PETSC_SUCCESS);
375 }
376 
377 /* type of CVODE linear multistep method */
378 const char *const TSSundialsLmmTypes[] = {"", "ADAMS", "BDF", "TSSundialsLmmType", "SUNDIALS_", NULL};
379 /* type of G-S orthogonalization used by CVODE linear solver */
380 const char *const TSSundialsGramSchmidtTypes[] = {"", "MODIFIED", "CLASSICAL", "TSSundialsGramSchmidtType", "SUNDIALS_", NULL};
381 
382 PetscErrorCode TSSetFromOptions_Sundials(TS ts, PetscOptionItems *PetscOptionsObject)
383 {
384   TS_Sundials *cvode = (TS_Sundials *)ts->data;
385   int          indx;
386   PetscBool    flag;
387   PC           pc;
388 
389   PetscFunctionBegin;
390   PetscOptionsHeadBegin(PetscOptionsObject, "SUNDIALS ODE solver options");
391   PetscCall(PetscOptionsEList("-ts_sundials_type", "Scheme", "TSSundialsSetType", TSSundialsLmmTypes, 3, TSSundialsLmmTypes[cvode->cvode_type], &indx, &flag));
392   if (flag) PetscCall(TSSundialsSetType(ts, (TSSundialsLmmType)indx));
393   PetscCall(PetscOptionsEList("-ts_sundials_gramschmidt_type", "Type of orthogonalization", "TSSundialsSetGramSchmidtType", TSSundialsGramSchmidtTypes, 3, TSSundialsGramSchmidtTypes[cvode->gtype], &indx, &flag));
394   if (flag) PetscCall(TSSundialsSetGramSchmidtType(ts, (TSSundialsGramSchmidtType)indx));
395   PetscCall(PetscOptionsReal("-ts_sundials_atol", "Absolute tolerance for convergence", "TSSundialsSetTolerance", cvode->abstol, &cvode->abstol, NULL));
396   PetscCall(PetscOptionsReal("-ts_sundials_rtol", "Relative tolerance for convergence", "TSSundialsSetTolerance", cvode->reltol, &cvode->reltol, NULL));
397   PetscCall(PetscOptionsReal("-ts_sundials_mindt", "Minimum step size", "TSSundialsSetMinTimeStep", cvode->mindt, &cvode->mindt, NULL));
398   PetscCall(PetscOptionsReal("-ts_sundials_maxdt", "Maximum step size", "TSSundialsSetMaxTimeStep", cvode->maxdt, &cvode->maxdt, NULL));
399   PetscCall(PetscOptionsReal("-ts_sundials_linear_tolerance", "Convergence tolerance for linear solve", "TSSundialsSetLinearTolerance", cvode->linear_tol, &cvode->linear_tol, NULL));
400   PetscCall(PetscOptionsInt("-ts_sundials_maxord", "Max Order for BDF/Adams method", "TSSundialsSetMaxOrd", cvode->maxord, &cvode->maxord, NULL));
401   PetscCall(PetscOptionsInt("-ts_sundials_maxl", "Max dimension of the Krylov subspace", "TSSundialsSetMaxl", cvode->maxl, &cvode->maxl, NULL));
402   PetscCall(PetscOptionsBool("-ts_sundials_monitor_steps", "Monitor SUNDIALS internal steps", "TSSundialsMonitorInternalSteps", cvode->monitorstep, &cvode->monitorstep, NULL));
403   PetscCall(PetscOptionsBool("-ts_sundials_use_dense", "Use dense internal solver in SUNDIALS (serial only)", "TSSundialsSetUseDense", cvode->use_dense, &cvode->use_dense, NULL));
404   PetscOptionsHeadEnd();
405   PetscCall(TSSundialsGetPC(ts, &pc));
406   PetscCall(PCSetFromOptions(pc));
407   PetscFunctionReturn(PETSC_SUCCESS);
408 }
409 
410 PetscErrorCode TSView_Sundials(TS ts, PetscViewer viewer)
411 {
412   TS_Sundials *cvode = (TS_Sundials *)ts->data;
413   char        *type;
414   char         atype[] = "Adams";
415   char         btype[] = "BDF: backward differentiation formula";
416   PetscBool    iascii, isstring;
417   long int     nsteps, its, nfevals, nlinsetups, nfails, itmp;
418   PetscInt     qlast, qcur;
419   PetscReal    hinused, hlast, hcur, tcur, tolsfac;
420   PC           pc;
421 
422   PetscFunctionBegin;
423   if (cvode->cvode_type == SUNDIALS_ADAMS) type = atype;
424   else type = btype;
425 
426   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
427   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
428   if (iascii) {
429     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS integrator does not use SNES!\n"));
430     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS integrator type %s\n", type));
431     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS maxord %" PetscInt_FMT "\n", cvode->maxord));
432     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS abs tol %g rel tol %g\n", (double)cvode->abstol, (double)cvode->reltol));
433     if (cvode->use_dense) {
434       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS integrator using a dense linear solve\n"));
435     } else {
436       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS linear solver tolerance factor %g\n", (double)cvode->linear_tol));
437       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS max dimension of Krylov subspace %" PetscInt_FMT "\n", cvode->maxl));
438       if (cvode->gtype == SUNDIALS_MODIFIED_GS) {
439         PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS using modified Gram-Schmidt for orthogonalization in GMRES\n"));
440       } else {
441         PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS using unmodified (classical) Gram-Schmidt for orthogonalization in GMRES\n"));
442       }
443     }
444     if (cvode->mindt > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS minimum time step %g\n", (double)cvode->mindt));
445     if (cvode->maxdt > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS maximum time step %g\n", (double)cvode->maxdt));
446 
447     /* Outputs from CVODE, CVSPILS */
448     PetscCallExternal(CVodeGetTolScaleFactor, cvode->mem, &tolsfac);
449     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS suggested factor for tolerance scaling %g\n", tolsfac));
450     PetscCallExternal(CVodeGetIntegratorStats, cvode->mem, &nsteps, &nfevals, &nlinsetups, &nfails, &qlast, &qcur, &hinused, &hlast, &hcur, &tcur);
451     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS cumulative number of internal steps %ld\n", nsteps));
452     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of calls to rhs function %ld\n", nfevals));
453     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of calls to linear solver setup function %ld\n", nlinsetups));
454     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of error test failures %ld\n", nfails));
455 
456     PetscCallExternal(CVodeGetNonlinSolvStats, cvode->mem, &its, &nfails);
457     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of nonlinear solver iterations %ld\n", its));
458     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of nonlinear convergence failure %ld\n", nfails));
459     if (!cvode->use_dense) {
460       PetscCallExternal(CVSpilsGetNumLinIters, cvode->mem, &its); /* its = no. of calls to TSPrecond_Sundials() */
461       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of linear iterations %ld\n", its));
462       PetscCallExternal(CVSpilsGetNumConvFails, cvode->mem, &itmp);
463       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of linear convergence failures %ld\n", itmp));
464 
465       PetscCall(TSSundialsGetPC(ts, &pc));
466       PetscCall(PCView(pc, viewer));
467       PetscCallExternal(CVSpilsGetNumPrecEvals, cvode->mem, &itmp);
468       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of preconditioner evaluations %ld\n", itmp));
469       PetscCallExternal(CVSpilsGetNumPrecSolves, cvode->mem, &itmp);
470       PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of preconditioner solves %ld\n", itmp));
471     }
472     PetscCallExternal(CVSpilsGetNumJtimesEvals, cvode->mem, &itmp);
473     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of Jacobian-vector product evaluations %ld\n", itmp));
474     PetscCallExternal(CVSpilsGetNumRhsEvals, cvode->mem, &itmp);
475     PetscCall(PetscViewerASCIIPrintf(viewer, "SUNDIALS no. of rhs calls for finite diff. Jacobian-vector evals %ld\n", itmp));
476   } else if (isstring) {
477     PetscCall(PetscViewerStringSPrintf(viewer, "SUNDIALS type %s", type));
478   }
479   PetscFunctionReturn(PETSC_SUCCESS);
480 }
481 
482 /* --------------------------------------------------------------------------*/
483 PetscErrorCode TSSundialsSetType_Sundials(TS ts, TSSundialsLmmType type)
484 {
485   TS_Sundials *cvode = (TS_Sundials *)ts->data;
486 
487   PetscFunctionBegin;
488   cvode->cvode_type = type;
489   PetscFunctionReturn(PETSC_SUCCESS);
490 }
491 
492 PetscErrorCode TSSundialsSetMaxl_Sundials(TS ts, PetscInt maxl)
493 {
494   TS_Sundials *cvode = (TS_Sundials *)ts->data;
495 
496   PetscFunctionBegin;
497   cvode->maxl = maxl;
498   PetscFunctionReturn(PETSC_SUCCESS);
499 }
500 
501 PetscErrorCode TSSundialsSetLinearTolerance_Sundials(TS ts, PetscReal tol)
502 {
503   TS_Sundials *cvode = (TS_Sundials *)ts->data;
504 
505   PetscFunctionBegin;
506   cvode->linear_tol = tol;
507   PetscFunctionReturn(PETSC_SUCCESS);
508 }
509 
510 PetscErrorCode TSSundialsSetGramSchmidtType_Sundials(TS ts, TSSundialsGramSchmidtType type)
511 {
512   TS_Sundials *cvode = (TS_Sundials *)ts->data;
513 
514   PetscFunctionBegin;
515   cvode->gtype = type;
516   PetscFunctionReturn(PETSC_SUCCESS);
517 }
518 
519 PetscErrorCode TSSundialsSetTolerance_Sundials(TS ts, PetscReal aabs, PetscReal rel)
520 {
521   TS_Sundials *cvode = (TS_Sundials *)ts->data;
522 
523   PetscFunctionBegin;
524   if (aabs != PETSC_DECIDE) cvode->abstol = aabs;
525   if (rel != PETSC_DECIDE) cvode->reltol = rel;
526   PetscFunctionReturn(PETSC_SUCCESS);
527 }
528 
529 PetscErrorCode TSSundialsSetMinTimeStep_Sundials(TS ts, PetscReal mindt)
530 {
531   TS_Sundials *cvode = (TS_Sundials *)ts->data;
532 
533   PetscFunctionBegin;
534   cvode->mindt = mindt;
535   PetscFunctionReturn(PETSC_SUCCESS);
536 }
537 
538 PetscErrorCode TSSundialsSetMaxTimeStep_Sundials(TS ts, PetscReal maxdt)
539 {
540   TS_Sundials *cvode = (TS_Sundials *)ts->data;
541 
542   PetscFunctionBegin;
543   cvode->maxdt = maxdt;
544   PetscFunctionReturn(PETSC_SUCCESS);
545 }
546 
547 PetscErrorCode TSSundialsSetUseDense_Sundials(TS ts, PetscBool use_dense)
548 {
549   TS_Sundials *cvode = (TS_Sundials *)ts->data;
550 
551   PetscFunctionBegin;
552   cvode->use_dense = use_dense;
553   PetscFunctionReturn(PETSC_SUCCESS);
554 }
555 
556 PetscErrorCode TSSundialsGetPC_Sundials(TS ts, PC *pc)
557 {
558   SNES snes;
559   KSP  ksp;
560 
561   PetscFunctionBegin;
562   PetscCall(TSGetSNES(ts, &snes));
563   PetscCall(SNESGetKSP(snes, &ksp));
564   PetscCall(KSPGetPC(ksp, pc));
565   PetscFunctionReturn(PETSC_SUCCESS);
566 }
567 
568 PetscErrorCode TSSundialsGetIterations_Sundials(TS ts, int *nonlin, int *lin)
569 {
570   PetscFunctionBegin;
571   if (nonlin) *nonlin = ts->snes_its;
572   if (lin) *lin = ts->ksp_its;
573   PetscFunctionReturn(PETSC_SUCCESS);
574 }
575 
576 PetscErrorCode TSSundialsMonitorInternalSteps_Sundials(TS ts, PetscBool s)
577 {
578   TS_Sundials *cvode = (TS_Sundials *)ts->data;
579 
580   PetscFunctionBegin;
581   cvode->monitorstep = s;
582   PetscFunctionReturn(PETSC_SUCCESS);
583 }
584 /* -------------------------------------------------------------------------------------------*/
585 
586 /*@C
587    TSSundialsGetIterations - Gets the number of nonlinear and linear iterations used so far by `TSSUNDIALS`.
588 
589    Not Collective
590 
591    Input Parameter:
592 .    ts     - the time-step context
593 
594    Output Parameters:
595 +   nonlin - number of nonlinear iterations
596 -   lin    - number of linear iterations
597 
598    Level: advanced
599 
600    Note:
601     These return the number since the creation of the `TS` object
602 
603 .seealso: [](chapter_ts), `TSSundialsSetType()`, `TSSundialsSetMaxl()`,
604           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
605           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
606           `TSSundialsSetLinearTolerance()`, `TSSundialsGetPC()`, `TSSetExactFinalTime()`
607 @*/
608 PetscErrorCode TSSundialsGetIterations(TS ts, int *nonlin, int *lin)
609 {
610   PetscFunctionBegin;
611   PetscUseMethod(ts, "TSSundialsGetIterations_C", (TS, int *, int *), (ts, nonlin, lin));
612   PetscFunctionReturn(PETSC_SUCCESS);
613 }
614 
615 /*@
616    TSSundialsSetType - Sets the method that `TSSUNDIALS` will use for integration.
617 
618    Logically Collective
619 
620    Input Parameters:
621 +    ts     - the time-step context
622 -    type   - one of  `SUNDIALS_ADAMS` or `SUNDIALS_BDF`
623 
624    Level: intermediate
625 
626 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetMaxl()`,
627           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
628           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
629           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
630           `TSSetExactFinalTime()`
631 @*/
632 PetscErrorCode TSSundialsSetType(TS ts, TSSundialsLmmType type)
633 {
634   PetscFunctionBegin;
635   PetscTryMethod(ts, "TSSundialsSetType_C", (TS, TSSundialsLmmType), (ts, type));
636   PetscFunctionReturn(PETSC_SUCCESS);
637 }
638 
639 /*@
640    TSSundialsSetMaxord - Sets the maximum order for BDF/Adams method used by `TSSUNDIALS`.
641 
642    Logically Collective
643 
644    Input Parameters:
645 +    ts      - the time-step context
646 -    maxord  - maximum order of BDF / Adams method
647 
648    Level: advanced
649 
650 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`,
651           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
652           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
653           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
654           `TSSetExactFinalTime()`
655 @*/
656 PetscErrorCode TSSundialsSetMaxord(TS ts, PetscInt maxord)
657 {
658   PetscFunctionBegin;
659   PetscValidLogicalCollectiveInt(ts, maxord, 2);
660   PetscTryMethod(ts, "TSSundialsSetMaxOrd_C", (TS, PetscInt), (ts, maxord));
661   PetscFunctionReturn(PETSC_SUCCESS);
662 }
663 
664 /*@
665    TSSundialsSetMaxl - Sets the dimension of the Krylov space used by
666        GMRES in the linear solver in `TSSUNDIALS`. `TSSUNDIALS` DOES NOT use restarted GMRES so
667        this is the maximum number of GMRES steps that will be used.
668 
669    Logically Collective
670 
671    Input Parameters:
672 +    ts      - the time-step context
673 -    maxl - number of direction vectors (the dimension of Krylov subspace).
674 
675    Level: advanced
676 
677 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`,
678           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
679           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
680           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
681           `TSSetExactFinalTime()`
682 @*/
683 PetscErrorCode TSSundialsSetMaxl(TS ts, PetscInt maxl)
684 {
685   PetscFunctionBegin;
686   PetscValidLogicalCollectiveInt(ts, maxl, 2);
687   PetscTryMethod(ts, "TSSundialsSetMaxl_C", (TS, PetscInt), (ts, maxl));
688   PetscFunctionReturn(PETSC_SUCCESS);
689 }
690 
691 /*@
692    TSSundialsSetLinearTolerance - Sets the tolerance used to solve the linear
693        system by `TSSUNDIALS`.
694 
695    Logically Collective
696 
697    Input Parameters:
698 +    ts     - the time-step context
699 -    tol    - the factor by which the tolerance on the nonlinear solver is
700              multiplied to get the tolerance on the linear solver, .05 by default.
701 
702    Level: advanced
703 
704 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`, `TSSundialsSetMaxl()`,
705           `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
706           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
707           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
708           `TSSetExactFinalTime()`
709 @*/
710 PetscErrorCode TSSundialsSetLinearTolerance(TS ts, PetscReal tol)
711 {
712   PetscFunctionBegin;
713   PetscValidLogicalCollectiveReal(ts, tol, 2);
714   PetscTryMethod(ts, "TSSundialsSetLinearTolerance_C", (TS, PetscReal), (ts, tol));
715   PetscFunctionReturn(PETSC_SUCCESS);
716 }
717 
718 /*@
719    TSSundialsSetGramSchmidtType - Sets type of orthogonalization used
720         in GMRES method by `TSSUNDIALS` linear solver.
721 
722    Logically Collective
723 
724    Input Parameters:
725 +    ts  - the time-step context
726 -    type - either `SUNDIALS_MODIFIED_GS` or `SUNDIALS_CLASSICAL_GS`
727 
728    Level: advanced
729 
730 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`, `TSSundialsSetMaxl()`,
731           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`,
732           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
733           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
734           `TSSetExactFinalTime()`
735 @*/
736 PetscErrorCode TSSundialsSetGramSchmidtType(TS ts, TSSundialsGramSchmidtType type)
737 {
738   PetscFunctionBegin;
739   PetscTryMethod(ts, "TSSundialsSetGramSchmidtType_C", (TS, TSSundialsGramSchmidtType), (ts, type));
740   PetscFunctionReturn(PETSC_SUCCESS);
741 }
742 
743 /*@
744    TSSundialsSetTolerance - Sets the absolute and relative tolerance used by
745                          `TSSUNDIALS` for error control.
746 
747    Logically Collective
748 
749    Input Parameters:
750 +    ts  - the time-step context
751 .    aabs - the absolute tolerance
752 -    rel - the relative tolerance
753 
754      See the CVODE/SUNDIALS users manual for exact details on these parameters. Essentially
755     these regulate the size of the error for a SINGLE timestep.
756 
757    Level: intermediate
758 
759 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`, `TSSundialsSetGMRESMaxl()`,
760           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`,
761           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
762           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`,
763           `TSSetExactFinalTime()`
764 @*/
765 PetscErrorCode TSSundialsSetTolerance(TS ts, PetscReal aabs, PetscReal rel)
766 {
767   PetscFunctionBegin;
768   PetscTryMethod(ts, "TSSundialsSetTolerance_C", (TS, PetscReal, PetscReal), (ts, aabs, rel));
769   PetscFunctionReturn(PETSC_SUCCESS);
770 }
771 
772 /*@
773    TSSundialsGetPC - Extract the PC context from a time-step context for `TSSUNDIALS`.
774 
775    Input Parameter:
776 .    ts - the time-step context
777 
778    Output Parameter:
779 .    pc - the preconditioner context
780 
781    Level: advanced
782 
783 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`, `TSSundialsSetMaxl()`,
784           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
785           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
786           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`
787 @*/
788 PetscErrorCode TSSundialsGetPC(TS ts, PC *pc)
789 {
790   PetscFunctionBegin;
791   PetscUseMethod(ts, "TSSundialsGetPC_C", (TS, PC *), (ts, pc));
792   PetscFunctionReturn(PETSC_SUCCESS);
793 }
794 
795 /*@
796    TSSundialsSetMinTimeStep - Smallest time step to be chosen by the adaptive controller.
797 
798    Input Parameters:
799 +   ts - the time-step context
800 -   mindt - lowest time step if positive, negative to deactivate
801 
802    Note:
803    `TSSUNDIALS` will error if it is not possible to keep the estimated truncation error below
804    the tolerance set with `TSSundialsSetTolerance()` without going below this step size.
805 
806    Level: beginner
807 
808 .seealso: [](chapter_ts), `TSSundialsSetType()`, `TSSundialsSetTolerance()`,
809 @*/
810 PetscErrorCode TSSundialsSetMinTimeStep(TS ts, PetscReal mindt)
811 {
812   PetscFunctionBegin;
813   PetscTryMethod(ts, "TSSundialsSetMinTimeStep_C", (TS, PetscReal), (ts, mindt));
814   PetscFunctionReturn(PETSC_SUCCESS);
815 }
816 
817 /*@
818    TSSundialsSetMaxTimeStep - Largest time step to be chosen by the adaptive controller.
819 
820    Input Parameters:
821 +   ts - the time-step context
822 -   maxdt - lowest time step if positive, negative to deactivate
823 
824    Level: beginner
825 
826 .seealso: [](chapter_ts), `TSSundialsSetType()`, `TSSundialsSetTolerance()`,
827 @*/
828 PetscErrorCode TSSundialsSetMaxTimeStep(TS ts, PetscReal maxdt)
829 {
830   PetscFunctionBegin;
831   PetscTryMethod(ts, "TSSundialsSetMaxTimeStep_C", (TS, PetscReal), (ts, maxdt));
832   PetscFunctionReturn(PETSC_SUCCESS);
833 }
834 
835 /*@
836    TSSundialsMonitorInternalSteps - Monitor `TSSUNDIALS` internal steps (Defaults to false).
837 
838    Input Parameters:
839 +   ts - the time-step context
840 -   ft - `PETSC_TRUE` if monitor, else `PETSC_FALSE`
841 
842    Level: beginner
843 
844 .seealso: [](chapter_ts), `TSSundialsGetIterations()`, `TSSundialsSetType()`, `TSSundialsSetMaxl()`,
845           `TSSundialsSetLinearTolerance()`, `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`,
846           `TSSundialsGetIterations()`, `TSSundialsSetType()`,
847           `TSSundialsSetLinearTolerance()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`
848 @*/
849 PetscErrorCode TSSundialsMonitorInternalSteps(TS ts, PetscBool ft)
850 {
851   PetscFunctionBegin;
852   PetscTryMethod(ts, "TSSundialsMonitorInternalSteps_C", (TS, PetscBool), (ts, ft));
853   PetscFunctionReturn(PETSC_SUCCESS);
854 }
855 
856 /*@
857    TSSundialsSetUseDense - Set a flag to use a dense linear solver in `TSSUNDIALS` (serial only)
858 
859    Logically Collective
860 
861    Input Parameters:
862 +    ts         - the time-step context
863 -    use_dense  - `PETSC_TRUE` to use the dense solver
864 
865    Level: advanced
866 
867 .seealso: [](chapter_ts), `TSSUNDIALS`
868 @*/
869 PetscErrorCode TSSundialsSetUseDense(TS ts, PetscBool use_dense)
870 {
871   PetscFunctionBegin;
872   PetscValidLogicalCollectiveInt(ts, use_dense, 2);
873   PetscTryMethod(ts, "TSSundialsSetUseDense_C", (TS, PetscBool), (ts, use_dense));
874   PetscFunctionReturn(PETSC_SUCCESS);
875 }
876 
877 /* -------------------------------------------------------------------------------------------*/
878 /*MC
879       TSSUNDIALS - ODE solver using a very old version of the LLNL CVODE/SUNDIALS package, version 2.5 (now called SUNDIALS). Requires ./configure --download-sundials
880 
881    Options Database Keys:
882 +    -ts_sundials_type <bdf,adams> -
883 .    -ts_sundials_gramschmidt_type <modified, classical> - type of orthogonalization inside GMRES
884 .    -ts_sundials_atol <tol> - Absolute tolerance for convergence
885 .    -ts_sundials_rtol <tol> - Relative tolerance for convergence
886 .    -ts_sundials_linear_tolerance <tol> -
887 .    -ts_sundials_maxl <maxl> - Max dimension of the Krylov subspace
888 .    -ts_sundials_monitor_steps - Monitor SUNDIALS internal steps
889 -    -ts_sundials_use_dense - Use a dense linear solver within CVODE (serial only)
890 
891     Level: beginner
892 
893     Note:
894     This uses its own nonlinear solver and Krylov method so PETSc `SNES` and `KSP` options do not apply,
895     only PETSc `PC` options.
896 
897 .seealso: [](chapter_ts), `TSCreate()`, `TS`, `TSSetType()`, `TSSundialsSetType()`, `TSSundialsSetMaxl()`, `TSSundialsSetLinearTolerance()`, `TSType`,
898           `TSSundialsSetGramSchmidtType()`, `TSSundialsSetTolerance()`, `TSSundialsGetPC()`, `TSSundialsGetIterations()`, `TSSetExactFinalTime()`
899 M*/
900 PETSC_EXTERN PetscErrorCode TSCreate_Sundials(TS ts)
901 {
902   TS_Sundials *cvode;
903   PC           pc;
904 
905   PetscFunctionBegin;
906   ts->ops->reset          = TSReset_Sundials;
907   ts->ops->destroy        = TSDestroy_Sundials;
908   ts->ops->view           = TSView_Sundials;
909   ts->ops->setup          = TSSetUp_Sundials;
910   ts->ops->step           = TSStep_Sundials;
911   ts->ops->interpolate    = TSInterpolate_Sundials;
912   ts->ops->setfromoptions = TSSetFromOptions_Sundials;
913   ts->default_adapt_type  = TSADAPTNONE;
914 
915   PetscCall(PetscNew(&cvode));
916 
917   ts->usessnes = PETSC_TRUE;
918 
919   ts->data           = (void *)cvode;
920   cvode->cvode_type  = SUNDIALS_BDF;
921   cvode->gtype       = SUNDIALS_CLASSICAL_GS;
922   cvode->maxl        = 5;
923   cvode->maxord      = PETSC_DEFAULT;
924   cvode->linear_tol  = .05;
925   cvode->monitorstep = PETSC_TRUE;
926   cvode->use_dense   = PETSC_FALSE;
927 
928   PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)ts), &(cvode->comm_sundials)));
929 
930   cvode->mindt = -1.;
931   cvode->maxdt = -1.;
932 
933   /* set tolerance for SUNDIALS */
934   cvode->reltol = 1e-6;
935   cvode->abstol = 1e-6;
936 
937   /* set PCNONE as default pctype */
938   PetscCall(TSSundialsGetPC_Sundials(ts, &pc));
939   PetscCall(PCSetType(pc, PCNONE));
940 
941   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetType_C", TSSundialsSetType_Sundials));
942   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMaxl_C", TSSundialsSetMaxl_Sundials));
943   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetLinearTolerance_C", TSSundialsSetLinearTolerance_Sundials));
944   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetGramSchmidtType_C", TSSundialsSetGramSchmidtType_Sundials));
945   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetTolerance_C", TSSundialsSetTolerance_Sundials));
946   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMinTimeStep_C", TSSundialsSetMinTimeStep_Sundials));
947   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetMaxTimeStep_C", TSSundialsSetMaxTimeStep_Sundials));
948   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsGetPC_C", TSSundialsGetPC_Sundials));
949   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsGetIterations_C", TSSundialsGetIterations_Sundials));
950   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsMonitorInternalSteps_C", TSSundialsMonitorInternalSteps_Sundials));
951   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSSundialsSetUseDense_C", TSSundialsSetUseDense_Sundials));
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954