xref: /petsc/src/ts/tutorials/ex31.c (revision 58d68138c660dfb4e9f5b03334792cd4f2ffd7cc)
1 static char help[] = "Solves the ordinary differential equations (IVPs) using explicit and implicit time-integration methods.\n";
2 
3 /*
4 
5   Useful command line parameters:
6   -problem <hull1972a1>: choose which problem to solve (see references
7                       for complete listing of problems).
8   -ts_type <euler>: specify time-integrator
9   -ts_adapt_type <basic>: specify time-step adapting (none,basic,advanced)
10   -refinement_levels <1>: number of refinement levels for convergence analysis
11   -refinement_factor <2.0>: factor to refine time step size by for convergence analysis
12   -dt <0.01>: specify time step (initial time step for convergence analysis)
13 
14 */
15 
16 /*
17 List of cases and their names in the code:-
18   From Hull, T.E., Enright, W.H., Fellen, B.M., and Sedgwick, A.E.,
19       "Comparing Numerical Methods for Ordinary Differential
20        Equations", SIAM J. Numer. Anal., 9(4), 1972, pp. 603 - 635
21     A1 -> "hull1972a1" (exact solution available)
22     A2 -> "hull1972a2" (exact solution available)
23     A3 -> "hull1972a3" (exact solution available)
24     A4 -> "hull1972a4" (exact solution available)
25     A5 -> "hull1972a5"
26     B1 -> "hull1972b1"
27     B2 -> "hull1972b2"
28     B3 -> "hull1972b3"
29     B4 -> "hull1972b4"
30     B5 -> "hull1972b5"
31     C1 -> "hull1972c1"
32     C2 -> "hull1972c2"
33     C3 -> "hull1972c3"
34     C4 -> "hull1972c4"
35 
36  From Constantinescu, E. "Estimating Global Errors in Time Stepping" ArXiv e-prints,
37        https://arxiv.org/abs/1503.05166, 2016
38 
39     Kulikov2013I -> "kulik2013i"
40 
41 */
42 
43 #include <petscts.h>
44 
45 /* Function declarations */
46 PetscErrorCode (*RHSFunction)(TS, PetscReal, Vec, Vec, void *);
47 PetscErrorCode (*RHSJacobian)(TS, PetscReal, Vec, Mat, Mat, void *);
48 PetscErrorCode (*IFunction)(TS, PetscReal, Vec, Vec, Vec, void *);
49 PetscErrorCode (*IJacobian)(TS, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *);
50 
51 /* Returns the size of the system of equations depending on problem specification */
52 PetscInt GetSize(const char *p) {
53   PetscFunctionBeginUser;
54   if ((!strcmp(p, "hull1972a1")) || (!strcmp(p, "hull1972a2")) || (!strcmp(p, "hull1972a3")) || (!strcmp(p, "hull1972a4")) || (!strcmp(p, "hull1972a5"))) PetscFunctionReturn(1);
55   else if (!strcmp(p, "hull1972b1")) PetscFunctionReturn(2);
56   else if ((!strcmp(p, "hull1972b2")) || (!strcmp(p, "hull1972b3")) || (!strcmp(p, "hull1972b4")) || (!strcmp(p, "hull1972b5"))) PetscFunctionReturn(3);
57   else if ((!strcmp(p, "kulik2013i"))) PetscFunctionReturn(4);
58   else if ((!strcmp(p, "hull1972c1")) || (!strcmp(p, "hull1972c2")) || (!strcmp(p, "hull1972c3"))) PetscFunctionReturn(10);
59   else if (!strcmp(p, "hull1972c4")) PetscFunctionReturn(51);
60   else PetscFunctionReturn(-1);
61 }
62 
63 /****************************************************************/
64 
65 /* Problem specific functions */
66 
67 /* Hull, 1972, Problem A1 */
68 
69 PetscErrorCode RHSFunction_Hull1972A1(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
70   PetscScalar       *f;
71   const PetscScalar *y;
72 
73   PetscFunctionBeginUser;
74   PetscCall(VecGetArrayRead(Y, &y));
75   PetscCall(VecGetArray(F, &f));
76   f[0] = -y[0];
77   PetscCall(VecRestoreArrayRead(Y, &y));
78   PetscCall(VecRestoreArray(F, &f));
79   PetscFunctionReturn(0);
80 }
81 
82 PetscErrorCode RHSJacobian_Hull1972A1(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
83   const PetscScalar *y;
84   PetscInt           row = 0, col = 0;
85   PetscScalar        value = -1.0;
86 
87   PetscFunctionBeginUser;
88   PetscCall(VecGetArrayRead(Y, &y));
89   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
90   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
91   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
92   PetscCall(VecRestoreArrayRead(Y, &y));
93   PetscFunctionReturn(0);
94 }
95 
96 PetscErrorCode IFunction_Hull1972A1(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
97   const PetscScalar *y;
98   PetscScalar       *f;
99 
100   PetscFunctionBeginUser;
101   PetscCall(VecGetArrayRead(Y, &y));
102   PetscCall(VecGetArray(F, &f));
103   f[0] = -y[0];
104   PetscCall(VecRestoreArrayRead(Y, &y));
105   PetscCall(VecRestoreArray(F, &f));
106   /* Left hand side = ydot - f(y) */
107   PetscCall(VecAYPX(F, -1.0, Ydot));
108   PetscFunctionReturn(0);
109 }
110 
111 PetscErrorCode IJacobian_Hull1972A1(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
112   const PetscScalar *y;
113   PetscInt           row = 0, col = 0;
114   PetscScalar        value = a - 1.0;
115 
116   PetscFunctionBeginUser;
117   PetscCall(VecGetArrayRead(Y, &y));
118   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
119   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
120   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
121   PetscCall(VecRestoreArrayRead(Y, &y));
122   PetscFunctionReturn(0);
123 }
124 
125 /* Hull, 1972, Problem A2 */
126 
127 PetscErrorCode RHSFunction_Hull1972A2(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
128   const PetscScalar *y;
129   PetscScalar       *f;
130 
131   PetscFunctionBeginUser;
132   PetscCall(VecGetArrayRead(Y, &y));
133   PetscCall(VecGetArray(F, &f));
134   f[0] = -0.5 * y[0] * y[0] * y[0];
135   PetscCall(VecRestoreArrayRead(Y, &y));
136   PetscCall(VecRestoreArray(F, &f));
137   PetscFunctionReturn(0);
138 }
139 
140 PetscErrorCode RHSJacobian_Hull1972A2(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
141   const PetscScalar *y;
142   PetscInt           row = 0, col = 0;
143   PetscScalar        value;
144 
145   PetscFunctionBeginUser;
146   PetscCall(VecGetArrayRead(Y, &y));
147   value = -0.5 * 3.0 * y[0] * y[0];
148   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
149   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
150   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
151   PetscCall(VecRestoreArrayRead(Y, &y));
152   PetscFunctionReturn(0);
153 }
154 
155 PetscErrorCode IFunction_Hull1972A2(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
156   PetscScalar       *f;
157   const PetscScalar *y;
158 
159   PetscFunctionBeginUser;
160   PetscCall(VecGetArrayRead(Y, &y));
161   PetscCall(VecGetArray(F, &f));
162   f[0] = -0.5 * y[0] * y[0] * y[0];
163   PetscCall(VecRestoreArrayRead(Y, &y));
164   PetscCall(VecRestoreArray(F, &f));
165   /* Left hand side = ydot - f(y) */
166   PetscCall(VecAYPX(F, -1.0, Ydot));
167   PetscFunctionReturn(0);
168 }
169 
170 PetscErrorCode IJacobian_Hull1972A2(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
171   const PetscScalar *y;
172   PetscInt           row = 0, col = 0;
173   PetscScalar        value;
174 
175   PetscFunctionBeginUser;
176   PetscCall(VecGetArrayRead(Y, &y));
177   value = a + 0.5 * 3.0 * y[0] * y[0];
178   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
179   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
180   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
181   PetscCall(VecRestoreArrayRead(Y, &y));
182   PetscFunctionReturn(0);
183 }
184 
185 /* Hull, 1972, Problem A3 */
186 
187 PetscErrorCode RHSFunction_Hull1972A3(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
188   const PetscScalar *y;
189   PetscScalar       *f;
190 
191   PetscFunctionBeginUser;
192   PetscCall(VecGetArrayRead(Y, &y));
193   PetscCall(VecGetArray(F, &f));
194   f[0] = y[0] * PetscCosReal(t);
195   PetscCall(VecRestoreArrayRead(Y, &y));
196   PetscCall(VecRestoreArray(F, &f));
197   PetscFunctionReturn(0);
198 }
199 
200 PetscErrorCode RHSJacobian_Hull1972A3(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
201   const PetscScalar *y;
202   PetscInt           row = 0, col = 0;
203   PetscScalar        value = PetscCosReal(t);
204 
205   PetscFunctionBeginUser;
206   PetscCall(VecGetArrayRead(Y, &y));
207   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
208   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
209   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
210   PetscCall(VecRestoreArrayRead(Y, &y));
211   PetscFunctionReturn(0);
212 }
213 
214 PetscErrorCode IFunction_Hull1972A3(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
215   PetscScalar       *f;
216   const PetscScalar *y;
217 
218   PetscFunctionBeginUser;
219   PetscCall(VecGetArrayRead(Y, &y));
220   PetscCall(VecGetArray(F, &f));
221   f[0] = y[0] * PetscCosReal(t);
222   PetscCall(VecRestoreArrayRead(Y, &y));
223   PetscCall(VecRestoreArray(F, &f));
224   /* Left hand side = ydot - f(y) */
225   PetscCall(VecAYPX(F, -1.0, Ydot));
226   PetscFunctionReturn(0);
227 }
228 
229 PetscErrorCode IJacobian_Hull1972A3(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
230   const PetscScalar *y;
231   PetscInt           row = 0, col = 0;
232   PetscScalar        value = a - PetscCosReal(t);
233 
234   PetscFunctionBeginUser;
235   PetscCall(VecGetArrayRead(Y, &y));
236   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
237   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
238   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
239   PetscCall(VecRestoreArrayRead(Y, &y));
240   PetscFunctionReturn(0);
241 }
242 
243 /* Hull, 1972, Problem A4 */
244 
245 PetscErrorCode RHSFunction_Hull1972A4(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
246   PetscScalar       *f;
247   const PetscScalar *y;
248 
249   PetscFunctionBeginUser;
250   PetscCall(VecGetArrayRead(Y, &y));
251   PetscCall(VecGetArray(F, &f));
252   f[0] = (0.25 * y[0]) * (1.0 - 0.05 * y[0]);
253   PetscCall(VecRestoreArrayRead(Y, &y));
254   PetscCall(VecRestoreArray(F, &f));
255   PetscFunctionReturn(0);
256 }
257 
258 PetscErrorCode RHSJacobian_Hull1972A4(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
259   const PetscScalar *y;
260   PetscInt           row = 0, col = 0;
261   PetscScalar        value;
262 
263   PetscFunctionBeginUser;
264   PetscCall(VecGetArrayRead(Y, &y));
265   value = 0.25 * (1.0 - 0.05 * y[0]) - (0.25 * y[0]) * 0.05;
266   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
267   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
268   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
269   PetscCall(VecRestoreArrayRead(Y, &y));
270   PetscFunctionReturn(0);
271 }
272 
273 PetscErrorCode IFunction_Hull1972A4(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
274   PetscScalar       *f;
275   const PetscScalar *y;
276 
277   PetscFunctionBeginUser;
278   PetscCall(VecGetArrayRead(Y, &y));
279   PetscCall(VecGetArray(F, &f));
280   f[0] = (0.25 * y[0]) * (1.0 - 0.05 * y[0]);
281   PetscCall(VecRestoreArrayRead(Y, &y));
282   PetscCall(VecRestoreArray(F, &f));
283   /* Left hand side = ydot - f(y) */
284   PetscCall(VecAYPX(F, -1.0, Ydot));
285   PetscFunctionReturn(0);
286 }
287 
288 PetscErrorCode IJacobian_Hull1972A4(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
289   const PetscScalar *y;
290   PetscInt           row = 0, col = 0;
291   PetscScalar        value;
292 
293   PetscFunctionBeginUser;
294   PetscCall(VecGetArrayRead(Y, &y));
295   value = a - 0.25 * (1.0 - 0.05 * y[0]) + (0.25 * y[0]) * 0.05;
296   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
297   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
298   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
299   PetscCall(VecRestoreArrayRead(Y, &y));
300   PetscFunctionReturn(0);
301 }
302 
303 /* Hull, 1972, Problem A5 */
304 
305 PetscErrorCode RHSFunction_Hull1972A5(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
306   PetscScalar       *f;
307   const PetscScalar *y;
308 
309   PetscFunctionBeginUser;
310   PetscCall(VecGetArrayRead(Y, &y));
311   PetscCall(VecGetArray(F, &f));
312   f[0] = (y[0] - t) / (y[0] + t);
313   PetscCall(VecRestoreArrayRead(Y, &y));
314   PetscCall(VecRestoreArray(F, &f));
315   PetscFunctionReturn(0);
316 }
317 
318 PetscErrorCode RHSJacobian_Hull1972A5(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
319   const PetscScalar *y;
320   PetscInt           row = 0, col = 0;
321   PetscScalar        value;
322 
323   PetscFunctionBeginUser;
324   PetscCall(VecGetArrayRead(Y, &y));
325   value = 2 * t / ((t + y[0]) * (t + y[0]));
326   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
327   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
328   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
329   PetscCall(VecRestoreArrayRead(Y, &y));
330   PetscFunctionReturn(0);
331 }
332 
333 PetscErrorCode IFunction_Hull1972A5(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
334   PetscScalar       *f;
335   const PetscScalar *y;
336 
337   PetscFunctionBeginUser;
338   PetscCall(VecGetArrayRead(Y, &y));
339   PetscCall(VecGetArray(F, &f));
340   f[0] = (y[0] - t) / (y[0] + t);
341   PetscCall(VecRestoreArrayRead(Y, &y));
342   PetscCall(VecRestoreArray(F, &f));
343   /* Left hand side = ydot - f(y) */
344   PetscCall(VecAYPX(F, -1.0, Ydot));
345   PetscFunctionReturn(0);
346 }
347 
348 PetscErrorCode IJacobian_Hull1972A5(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
349   const PetscScalar *y;
350   PetscInt           row = 0, col = 0;
351   PetscScalar        value;
352 
353   PetscFunctionBeginUser;
354   PetscCall(VecGetArrayRead(Y, &y));
355   value = a - 2 * t / ((t + y[0]) * (t + y[0]));
356   PetscCall(MatSetValues(A, 1, &row, 1, &col, &value, INSERT_VALUES));
357   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
358   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
359   PetscCall(VecRestoreArrayRead(Y, &y));
360   PetscFunctionReturn(0);
361 }
362 
363 /* Hull, 1972, Problem B1 */
364 
365 PetscErrorCode RHSFunction_Hull1972B1(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
366   PetscScalar       *f;
367   const PetscScalar *y;
368 
369   PetscFunctionBeginUser;
370   PetscCall(VecGetArrayRead(Y, &y));
371   PetscCall(VecGetArray(F, &f));
372   f[0] = 2.0 * (y[0] - y[0] * y[1]);
373   f[1] = -(y[1] - y[0] * y[1]);
374   PetscCall(VecRestoreArrayRead(Y, &y));
375   PetscCall(VecRestoreArray(F, &f));
376   PetscFunctionReturn(0);
377 }
378 
379 PetscErrorCode IFunction_Hull1972B1(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
380   PetscScalar       *f;
381   const PetscScalar *y;
382 
383   PetscFunctionBeginUser;
384   PetscCall(VecGetArrayRead(Y, &y));
385   PetscCall(VecGetArray(F, &f));
386   f[0] = 2.0 * (y[0] - y[0] * y[1]);
387   f[1] = -(y[1] - y[0] * y[1]);
388   PetscCall(VecRestoreArrayRead(Y, &y));
389   PetscCall(VecRestoreArray(F, &f));
390   /* Left hand side = ydot - f(y) */
391   PetscCall(VecAYPX(F, -1.0, Ydot));
392   PetscFunctionReturn(0);
393 }
394 
395 PetscErrorCode IJacobian_Hull1972B1(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
396   const PetscScalar *y;
397   PetscInt           row[2] = {0, 1};
398   PetscScalar        value[2][2];
399 
400   PetscFunctionBeginUser;
401   PetscCall(VecGetArrayRead(Y, &y));
402   value[0][0] = a - 2.0 * (1.0 - y[1]);
403   value[0][1] = 2.0 * y[0];
404   value[1][0] = -y[1];
405   value[1][1] = a + 1.0 - y[0];
406   PetscCall(MatSetValues(A, 2, &row[0], 2, &row[0], &value[0][0], INSERT_VALUES));
407   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
408   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
409   PetscCall(VecRestoreArrayRead(Y, &y));
410   PetscFunctionReturn(0);
411 }
412 
413 /* Hull, 1972, Problem B2 */
414 
415 PetscErrorCode RHSFunction_Hull1972B2(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
416   PetscScalar       *f;
417   const PetscScalar *y;
418 
419   PetscFunctionBeginUser;
420   PetscCall(VecGetArrayRead(Y, &y));
421   PetscCall(VecGetArray(F, &f));
422   f[0] = -y[0] + y[1];
423   f[1] = y[0] - 2.0 * y[1] + y[2];
424   f[2] = y[1] - y[2];
425   PetscCall(VecRestoreArrayRead(Y, &y));
426   PetscCall(VecRestoreArray(F, &f));
427   PetscFunctionReturn(0);
428 }
429 
430 PetscErrorCode IFunction_Hull1972B2(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
431   PetscScalar       *f;
432   const PetscScalar *y;
433 
434   PetscFunctionBeginUser;
435   PetscCall(VecGetArrayRead(Y, &y));
436   PetscCall(VecGetArray(F, &f));
437   f[0] = -y[0] + y[1];
438   f[1] = y[0] - 2.0 * y[1] + y[2];
439   f[2] = y[1] - y[2];
440   PetscCall(VecRestoreArrayRead(Y, &y));
441   PetscCall(VecRestoreArray(F, &f));
442   /* Left hand side = ydot - f(y) */
443   PetscCall(VecAYPX(F, -1.0, Ydot));
444   PetscFunctionReturn(0);
445 }
446 
447 PetscErrorCode IJacobian_Hull1972B2(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
448   const PetscScalar *y;
449   PetscInt           row[3] = {0, 1, 2};
450   PetscScalar        value[3][3];
451 
452   PetscFunctionBeginUser;
453   PetscCall(VecGetArrayRead(Y, &y));
454   value[0][0] = a + 1.0;
455   value[0][1] = -1.0;
456   value[0][2] = 0;
457   value[1][0] = -1.0;
458   value[1][1] = a + 2.0;
459   value[1][2] = -1.0;
460   value[2][0] = 0;
461   value[2][1] = -1.0;
462   value[2][2] = a + 1.0;
463   PetscCall(MatSetValues(A, 3, &row[0], 3, &row[0], &value[0][0], INSERT_VALUES));
464   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
465   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
466   PetscCall(VecRestoreArrayRead(Y, &y));
467   PetscFunctionReturn(0);
468 }
469 
470 /* Hull, 1972, Problem B3 */
471 
472 PetscErrorCode RHSFunction_Hull1972B3(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
473   PetscScalar       *f;
474   const PetscScalar *y;
475 
476   PetscFunctionBeginUser;
477   PetscCall(VecGetArrayRead(Y, &y));
478   PetscCall(VecGetArray(F, &f));
479   f[0] = -y[0];
480   f[1] = y[0] - y[1] * y[1];
481   f[2] = y[1] * y[1];
482   PetscCall(VecRestoreArrayRead(Y, &y));
483   PetscCall(VecRestoreArray(F, &f));
484   PetscFunctionReturn(0);
485 }
486 
487 PetscErrorCode IFunction_Hull1972B3(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
488   PetscScalar       *f;
489   const PetscScalar *y;
490 
491   PetscFunctionBeginUser;
492   PetscCall(VecGetArrayRead(Y, &y));
493   PetscCall(VecGetArray(F, &f));
494   f[0] = -y[0];
495   f[1] = y[0] - y[1] * y[1];
496   f[2] = y[1] * y[1];
497   PetscCall(VecRestoreArrayRead(Y, &y));
498   PetscCall(VecRestoreArray(F, &f));
499   /* Left hand side = ydot - f(y) */
500   PetscCall(VecAYPX(F, -1.0, Ydot));
501   PetscFunctionReturn(0);
502 }
503 
504 PetscErrorCode IJacobian_Hull1972B3(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
505   const PetscScalar *y;
506   PetscInt           row[3] = {0, 1, 2};
507   PetscScalar        value[3][3];
508 
509   PetscFunctionBeginUser;
510   PetscCall(VecGetArrayRead(Y, &y));
511   value[0][0] = a + 1.0;
512   value[0][1] = 0;
513   value[0][2] = 0;
514   value[1][0] = -1.0;
515   value[1][1] = a + 2.0 * y[1];
516   value[1][2] = 0;
517   value[2][0] = 0;
518   value[2][1] = -2.0 * y[1];
519   value[2][2] = a;
520   PetscCall(MatSetValues(A, 3, &row[0], 3, &row[0], &value[0][0], INSERT_VALUES));
521   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
522   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
523   PetscCall(VecRestoreArrayRead(Y, &y));
524   PetscFunctionReturn(0);
525 }
526 
527 /* Hull, 1972, Problem B4 */
528 
529 PetscErrorCode RHSFunction_Hull1972B4(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
530   PetscScalar       *f;
531   const PetscScalar *y;
532 
533   PetscFunctionBeginUser;
534   PetscCall(VecGetArrayRead(Y, &y));
535   PetscCall(VecGetArray(F, &f));
536   f[0] = -y[1] - y[0] * y[2] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
537   f[1] = y[0] - y[1] * y[2] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
538   f[2] = y[0] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
539   PetscCall(VecRestoreArrayRead(Y, &y));
540   PetscCall(VecRestoreArray(F, &f));
541   PetscFunctionReturn(0);
542 }
543 
544 PetscErrorCode IFunction_Hull1972B4(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
545   PetscScalar       *f;
546   const PetscScalar *y;
547 
548   PetscFunctionBeginUser;
549   PetscCall(VecGetArrayRead(Y, &y));
550   PetscCall(VecGetArray(F, &f));
551   f[0] = -y[1] - y[0] * y[2] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
552   f[1] = y[0] - y[1] * y[2] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
553   f[2] = y[0] / PetscSqrtScalar(y[0] * y[0] + y[1] * y[1]);
554   PetscCall(VecRestoreArrayRead(Y, &y));
555   PetscCall(VecRestoreArray(F, &f));
556   /* Left hand side = ydot - f(y) */
557   PetscCall(VecAYPX(F, -1.0, Ydot));
558   PetscFunctionReturn(0);
559 }
560 
561 PetscErrorCode IJacobian_Hull1972B4(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
562   const PetscScalar *y;
563   PetscInt           row[3] = {0, 1, 2};
564   PetscScalar        value[3][3], fac, fac2;
565 
566   PetscFunctionBeginUser;
567   PetscCall(VecGetArrayRead(Y, &y));
568   fac         = PetscPowScalar(y[0] * y[0] + y[1] * y[1], -1.5);
569   fac2        = PetscPowScalar(y[0] * y[0] + y[1] * y[1], -0.5);
570   value[0][0] = a + (y[1] * y[1] * y[2]) * fac;
571   value[0][1] = 1.0 - (y[0] * y[1] * y[2]) * fac;
572   value[0][2] = y[0] * fac2;
573   value[1][0] = -1.0 - y[0] * y[1] * y[2] * fac;
574   value[1][1] = a + y[0] * y[0] * y[2] * fac;
575   value[1][2] = y[1] * fac2;
576   value[2][0] = -y[1] * y[1] * fac;
577   value[2][1] = y[0] * y[1] * fac;
578   value[2][2] = a;
579   PetscCall(MatSetValues(A, 3, &row[0], 3, &row[0], &value[0][0], INSERT_VALUES));
580   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
581   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
582   PetscCall(VecRestoreArrayRead(Y, &y));
583   PetscFunctionReturn(0);
584 }
585 
586 /* Hull, 1972, Problem B5 */
587 
588 PetscErrorCode RHSFunction_Hull1972B5(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
589   PetscScalar       *f;
590   const PetscScalar *y;
591 
592   PetscFunctionBeginUser;
593   PetscCall(VecGetArrayRead(Y, &y));
594   PetscCall(VecGetArray(F, &f));
595   f[0] = y[1] * y[2];
596   f[1] = -y[0] * y[2];
597   f[2] = -0.51 * y[0] * y[1];
598   PetscCall(VecRestoreArrayRead(Y, &y));
599   PetscCall(VecRestoreArray(F, &f));
600   PetscFunctionReturn(0);
601 }
602 
603 PetscErrorCode IFunction_Hull1972B5(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
604   PetscScalar       *f;
605   const PetscScalar *y;
606 
607   PetscFunctionBeginUser;
608   PetscCall(VecGetArrayRead(Y, &y));
609   PetscCall(VecGetArray(F, &f));
610   f[0] = y[1] * y[2];
611   f[1] = -y[0] * y[2];
612   f[2] = -0.51 * y[0] * y[1];
613   PetscCall(VecRestoreArrayRead(Y, &y));
614   PetscCall(VecRestoreArray(F, &f));
615   /* Left hand side = ydot - f(y) */
616   PetscCall(VecAYPX(F, -1.0, Ydot));
617   PetscFunctionReturn(0);
618 }
619 
620 PetscErrorCode IJacobian_Hull1972B5(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
621   const PetscScalar *y;
622   PetscInt           row[3] = {0, 1, 2};
623   PetscScalar        value[3][3];
624 
625   PetscFunctionBeginUser;
626   PetscCall(VecGetArrayRead(Y, &y));
627   value[0][0] = a;
628   value[0][1] = -y[2];
629   value[0][2] = -y[1];
630   value[1][0] = y[2];
631   value[1][1] = a;
632   value[1][2] = y[0];
633   value[2][0] = 0.51 * y[1];
634   value[2][1] = 0.51 * y[0];
635   value[2][2] = a;
636   PetscCall(MatSetValues(A, 3, &row[0], 3, &row[0], &value[0][0], INSERT_VALUES));
637   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
638   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
639   PetscCall(VecRestoreArrayRead(Y, &y));
640   PetscFunctionReturn(0);
641 }
642 
643 /* Kulikov, 2013, Problem I */
644 
645 PetscErrorCode RHSFunction_Kulikov2013I(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
646   PetscScalar       *f;
647   const PetscScalar *y;
648 
649   PetscFunctionBeginUser;
650   PetscCall(VecGetArrayRead(Y, &y));
651   PetscCall(VecGetArray(F, &f));
652   f[0] = 2. * t * PetscPowScalar(y[1], 1. / 5.) * y[3];
653   f[1] = 10. * t * y[3] * PetscExpScalar(5.0 * (y[2] - 1.));
654   f[2] = 2. * t * y[3];
655   f[3] = -2. * t * PetscLogScalar(y[0]);
656   PetscCall(VecRestoreArrayRead(Y, &y));
657   PetscCall(VecRestoreArray(F, &f));
658   PetscFunctionReturn(0);
659 }
660 
661 PetscErrorCode RHSJacobian_Kulikov2013I(TS ts, PetscReal t, Vec Y, Mat A, Mat B, void *s) {
662   const PetscScalar *y;
663   PetscInt           row[4] = {0, 1, 2, 3};
664   PetscScalar        value[4][4];
665   PetscScalar        m1, m2;
666   PetscFunctionBeginUser;
667   PetscCall(VecGetArrayRead(Y, &y));
668   m1          = (2. * t * y[3]) / (5. * PetscPowScalar(y[1], 4. / 5.));
669   m2          = 2. * t * PetscPowScalar(y[1], 1. / 5.);
670   value[0][0] = 0.;
671   value[0][1] = m1;
672   value[0][2] = 0.;
673   value[0][3] = m2;
674   m1          = 50. * t * y[3] * PetscExpScalar(5.0 * (y[2] - 1.));
675   m2          = 10. * t * PetscExpScalar(5.0 * (y[2] - 1.));
676   value[1][0] = 0.;
677   value[1][1] = 0.;
678   value[1][2] = m1;
679   value[1][3] = m2;
680   value[2][0] = 0.;
681   value[2][1] = 0.;
682   value[2][2] = 0.;
683   value[2][3] = 2 * t;
684   value[3][0] = -2. * t / y[0];
685   value[3][1] = 0.;
686   value[3][2] = 0.;
687   value[3][3] = 0.;
688   PetscCall(MatSetValues(A, 4, &row[0], 4, &row[0], &value[0][0], INSERT_VALUES));
689   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
690   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
691   PetscCall(VecRestoreArrayRead(Y, &y));
692   PetscFunctionReturn(0);
693 }
694 
695 PetscErrorCode IFunction_Kulikov2013I(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
696   PetscScalar       *f;
697   const PetscScalar *y;
698 
699   PetscFunctionBeginUser;
700   PetscCall(VecGetArrayRead(Y, &y));
701   PetscCall(VecGetArray(F, &f));
702   f[0] = 2. * t * PetscPowScalar(y[1], 1. / 5.) * y[3];
703   f[1] = 10. * t * y[3] * PetscExpScalar(5.0 * (y[2] - 1.));
704   f[2] = 2. * t * y[3];
705   f[3] = -2. * t * PetscLogScalar(y[0]);
706   PetscCall(VecRestoreArrayRead(Y, &y));
707   PetscCall(VecRestoreArray(F, &f));
708   /* Left hand side = ydot - f(y) */
709   PetscCall(VecAYPX(F, -1.0, Ydot));
710   PetscFunctionReturn(0);
711 }
712 
713 PetscErrorCode IJacobian_Kulikov2013I(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
714   const PetscScalar *y;
715   PetscInt           row[4] = {0, 1, 2, 3};
716   PetscScalar        value[4][4];
717   PetscScalar        m1, m2;
718 
719   PetscFunctionBeginUser;
720   PetscCall(VecGetArrayRead(Y, &y));
721   m1          = (2. * t * y[3]) / (5. * PetscPowScalar(y[1], 4. / 5.));
722   m2          = 2. * t * PetscPowScalar(y[1], 1. / 5.);
723   value[0][0] = a;
724   value[0][1] = m1;
725   value[0][2] = 0.;
726   value[0][3] = m2;
727   m1          = 50. * t * y[3] * PetscExpScalar(5.0 * (y[2] - 1.));
728   m2          = 10. * t * PetscExpScalar(5.0 * (y[2] - 1.));
729   value[1][0] = 0.;
730   value[1][1] = a;
731   value[1][2] = m1;
732   value[1][3] = m2;
733   value[2][0] = 0.;
734   value[2][1] = 0.;
735   value[2][2] = a;
736   value[2][3] = 2 * t;
737   value[3][0] = -2. * t / y[0];
738   value[3][1] = 0.;
739   value[3][2] = 0.;
740   value[3][3] = a;
741   PetscCall(MatSetValues(A, 4, &row[0], 4, &row[0], &value[0][0], INSERT_VALUES));
742   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
743   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
744   PetscCall(VecRestoreArrayRead(Y, &y));
745   PetscFunctionReturn(0);
746 }
747 
748 /* Hull, 1972, Problem C1 */
749 
750 PetscErrorCode RHSFunction_Hull1972C1(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
751   PetscScalar       *f;
752   const PetscScalar *y;
753   PetscInt           N, i;
754 
755   PetscFunctionBeginUser;
756   PetscCall(VecGetSize(Y, &N));
757   PetscCall(VecGetArrayRead(Y, &y));
758   PetscCall(VecGetArray(F, &f));
759   f[0] = -y[0];
760   for (i = 1; i < N - 1; i++) { f[i] = y[i - 1] - y[i]; }
761   f[N - 1] = y[N - 2];
762   PetscCall(VecRestoreArrayRead(Y, &y));
763   PetscCall(VecRestoreArray(F, &f));
764   PetscFunctionReturn(0);
765 }
766 
767 PetscErrorCode IFunction_Hull1972C1(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
768   PetscScalar       *f;
769   const PetscScalar *y;
770   PetscInt           N, i;
771 
772   PetscFunctionBeginUser;
773   PetscCall(VecGetSize(Y, &N));
774   PetscCall(VecGetArrayRead(Y, &y));
775   PetscCall(VecGetArray(F, &f));
776   f[0] = -y[0];
777   for (i = 1; i < N - 1; i++) { f[i] = y[i - 1] - y[i]; }
778   f[N - 1] = y[N - 2];
779   PetscCall(VecRestoreArrayRead(Y, &y));
780   PetscCall(VecRestoreArray(F, &f));
781   /* Left hand side = ydot - f(y) */
782   PetscCall(VecAYPX(F, -1.0, Ydot));
783   PetscFunctionReturn(0);
784 }
785 
786 PetscErrorCode IJacobian_Hull1972C1(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
787   const PetscScalar *y;
788   PetscInt           N, i, col[2];
789   PetscScalar        value[2];
790 
791   PetscFunctionBeginUser;
792   PetscCall(VecGetSize(Y, &N));
793   PetscCall(VecGetArrayRead(Y, &y));
794   i        = 0;
795   value[0] = a + 1;
796   col[0]   = 0;
797   value[1] = 0;
798   col[1]   = 1;
799   PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
800   for (i = 0; i < N; i++) {
801     value[0] = -1;
802     col[0]   = i - 1;
803     value[1] = a + 1;
804     col[1]   = i;
805     PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
806   }
807   i        = N - 1;
808   value[0] = -1;
809   col[0]   = N - 2;
810   value[1] = a;
811   col[1]   = N - 1;
812   PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
813   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
814   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
815   PetscCall(VecRestoreArrayRead(Y, &y));
816   PetscFunctionReturn(0);
817 }
818 
819 /* Hull, 1972, Problem C2 */
820 
821 PetscErrorCode RHSFunction_Hull1972C2(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
822   const PetscScalar *y;
823   PetscScalar       *f;
824   PetscInt           N, i;
825 
826   PetscFunctionBeginUser;
827   PetscCall(VecGetSize(Y, &N));
828   PetscCall(VecGetArrayRead(Y, &y));
829   PetscCall(VecGetArray(F, &f));
830   f[0] = -y[0];
831   for (i = 1; i < N - 1; i++) { f[i] = (PetscReal)i * y[i - 1] - (PetscReal)(i + 1) * y[i]; }
832   f[N - 1] = (PetscReal)(N - 1) * y[N - 2];
833   PetscCall(VecRestoreArrayRead(Y, &y));
834   PetscCall(VecRestoreArray(F, &f));
835   PetscFunctionReturn(0);
836 }
837 
838 PetscErrorCode IFunction_Hull1972C2(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
839   PetscScalar       *f;
840   const PetscScalar *y;
841   PetscInt           N, i;
842 
843   PetscFunctionBeginUser;
844   PetscCall(VecGetSize(Y, &N));
845   PetscCall(VecGetArrayRead(Y, &y));
846   PetscCall(VecGetArray(F, &f));
847   f[0] = -y[0];
848   for (i = 1; i < N - 1; i++) { f[i] = (PetscReal)i * y[i - 1] - (PetscReal)(i + 1) * y[i]; }
849   f[N - 1] = (PetscReal)(N - 1) * y[N - 2];
850   PetscCall(VecRestoreArrayRead(Y, &y));
851   PetscCall(VecRestoreArray(F, &f));
852   /* Left hand side = ydot - f(y) */
853   PetscCall(VecAYPX(F, -1.0, Ydot));
854   PetscFunctionReturn(0);
855 }
856 
857 PetscErrorCode IJacobian_Hull1972C2(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
858   const PetscScalar *y;
859   PetscInt           N, i, col[2];
860   PetscScalar        value[2];
861 
862   PetscFunctionBeginUser;
863   PetscCall(VecGetSize(Y, &N));
864   PetscCall(VecGetArrayRead(Y, &y));
865   i        = 0;
866   value[0] = a + 1;
867   col[0]   = 0;
868   value[1] = 0;
869   col[1]   = 1;
870   PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
871   for (i = 0; i < N; i++) {
872     value[0] = -(PetscReal)i;
873     col[0]   = i - 1;
874     value[1] = a + (PetscReal)(i + 1);
875     col[1]   = i;
876     PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
877   }
878   i        = N - 1;
879   value[0] = -(PetscReal)(N - 1);
880   col[0]   = N - 2;
881   value[1] = a;
882   col[1]   = N - 1;
883   PetscCall(MatSetValues(A, 1, &i, 2, col, value, INSERT_VALUES));
884   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
885   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
886   PetscCall(VecRestoreArrayRead(Y, &y));
887   PetscFunctionReturn(0);
888 }
889 
890 /* Hull, 1972, Problem C3 and C4 */
891 
892 PetscErrorCode RHSFunction_Hull1972C34(TS ts, PetscReal t, Vec Y, Vec F, void *s) {
893   PetscScalar       *f;
894   const PetscScalar *y;
895   PetscInt           N, i;
896 
897   PetscFunctionBeginUser;
898   PetscCall(VecGetSize(Y, &N));
899   PetscCall(VecGetArrayRead(Y, &y));
900   PetscCall(VecGetArray(F, &f));
901   f[0] = -2.0 * y[0] + y[1];
902   for (i = 1; i < N - 1; i++) { f[i] = y[i - 1] - 2.0 * y[i] + y[i + 1]; }
903   f[N - 1] = y[N - 2] - 2.0 * y[N - 1];
904   PetscCall(VecRestoreArrayRead(Y, &y));
905   PetscCall(VecRestoreArray(F, &f));
906   PetscFunctionReturn(0);
907 }
908 
909 PetscErrorCode IFunction_Hull1972C34(TS ts, PetscReal t, Vec Y, Vec Ydot, Vec F, void *s) {
910   PetscScalar       *f;
911   const PetscScalar *y;
912   PetscInt           N, i;
913 
914   PetscFunctionBeginUser;
915   PetscCall(VecGetSize(Y, &N));
916   PetscCall(VecGetArrayRead(Y, &y));
917   PetscCall(VecGetArray(F, &f));
918   f[0] = -2.0 * y[0] + y[1];
919   for (i = 1; i < N - 1; i++) { f[i] = y[i - 1] - 2.0 * y[i] + y[i + 1]; }
920   f[N - 1] = y[N - 2] - 2.0 * y[N - 1];
921   PetscCall(VecRestoreArrayRead(Y, &y));
922   PetscCall(VecRestoreArray(F, &f));
923   /* Left hand side = ydot - f(y) */
924   PetscCall(VecAYPX(F, -1.0, Ydot));
925   PetscFunctionReturn(0);
926 }
927 
928 PetscErrorCode IJacobian_Hull1972C34(TS ts, PetscReal t, Vec Y, Vec Ydot, PetscReal a, Mat A, Mat B, void *s) {
929   const PetscScalar *y;
930   PetscScalar        value[3];
931   PetscInt           N, i, col[3];
932 
933   PetscFunctionBeginUser;
934   PetscCall(VecGetSize(Y, &N));
935   PetscCall(VecGetArrayRead(Y, &y));
936   for (i = 0; i < N; i++) {
937     if (i == 0) {
938       value[0] = a + 2;
939       col[0]   = i;
940       value[1] = -1;
941       col[1]   = i + 1;
942       value[2] = 0;
943       col[2]   = i + 2;
944     } else if (i == N - 1) {
945       value[0] = 0;
946       col[0]   = i - 2;
947       value[1] = -1;
948       col[1]   = i - 1;
949       value[2] = a + 2;
950       col[2]   = i;
951     } else {
952       value[0] = -1;
953       col[0]   = i - 1;
954       value[1] = a + 2;
955       col[1]   = i;
956       value[2] = -1;
957       col[2]   = i + 1;
958     }
959     PetscCall(MatSetValues(A, 1, &i, 3, col, value, INSERT_VALUES));
960   }
961   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
962   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
963   PetscCall(VecRestoreArrayRead(Y, &y));
964   PetscFunctionReturn(0);
965 }
966 
967 /***************************************************************************/
968 
969 /* Sets the initial solution for the IVP and sets up the function pointers*/
970 PetscErrorCode Initialize(Vec Y, void *s) {
971   char        *p = (char *)s;
972   PetscScalar *y;
973   PetscReal    t0;
974   PetscInt     N = GetSize((const char *)s);
975   PetscBool    flg;
976 
977   PetscFunctionBeginUser;
978   VecZeroEntries(Y);
979   PetscCall(VecGetArray(Y, &y));
980   if (!strcmp(p, "hull1972a1")) {
981     y[0]        = 1.0;
982     RHSFunction = RHSFunction_Hull1972A1;
983     RHSJacobian = RHSJacobian_Hull1972A1;
984     IFunction   = IFunction_Hull1972A1;
985     IJacobian   = IJacobian_Hull1972A1;
986   } else if (!strcmp(p, "hull1972a2")) {
987     y[0]        = 1.0;
988     RHSFunction = RHSFunction_Hull1972A2;
989     RHSJacobian = RHSJacobian_Hull1972A2;
990     IFunction   = IFunction_Hull1972A2;
991     IJacobian   = IJacobian_Hull1972A2;
992   } else if (!strcmp(p, "hull1972a3")) {
993     y[0]        = 1.0;
994     RHSFunction = RHSFunction_Hull1972A3;
995     RHSJacobian = RHSJacobian_Hull1972A3;
996     IFunction   = IFunction_Hull1972A3;
997     IJacobian   = IJacobian_Hull1972A3;
998   } else if (!strcmp(p, "hull1972a4")) {
999     y[0]        = 1.0;
1000     RHSFunction = RHSFunction_Hull1972A4;
1001     RHSJacobian = RHSJacobian_Hull1972A4;
1002     IFunction   = IFunction_Hull1972A4;
1003     IJacobian   = IJacobian_Hull1972A4;
1004   } else if (!strcmp(p, "hull1972a5")) {
1005     y[0]        = 4.0;
1006     RHSFunction = RHSFunction_Hull1972A5;
1007     RHSJacobian = RHSJacobian_Hull1972A5;
1008     IFunction   = IFunction_Hull1972A5;
1009     IJacobian   = IJacobian_Hull1972A5;
1010   } else if (!strcmp(p, "hull1972b1")) {
1011     y[0]        = 1.0;
1012     y[1]        = 3.0;
1013     RHSFunction = RHSFunction_Hull1972B1;
1014     IFunction   = IFunction_Hull1972B1;
1015     IJacobian   = IJacobian_Hull1972B1;
1016   } else if (!strcmp(p, "hull1972b2")) {
1017     y[0]        = 2.0;
1018     y[1]        = 0.0;
1019     y[2]        = 1.0;
1020     RHSFunction = RHSFunction_Hull1972B2;
1021     IFunction   = IFunction_Hull1972B2;
1022     IJacobian   = IJacobian_Hull1972B2;
1023   } else if (!strcmp(p, "hull1972b3")) {
1024     y[0]        = 1.0;
1025     y[1]        = 0.0;
1026     y[2]        = 0.0;
1027     RHSFunction = RHSFunction_Hull1972B3;
1028     IFunction   = IFunction_Hull1972B3;
1029     IJacobian   = IJacobian_Hull1972B3;
1030   } else if (!strcmp(p, "hull1972b4")) {
1031     y[0]        = 3.0;
1032     y[1]        = 0.0;
1033     y[2]        = 0.0;
1034     RHSFunction = RHSFunction_Hull1972B4;
1035     IFunction   = IFunction_Hull1972B4;
1036     IJacobian   = IJacobian_Hull1972B4;
1037   } else if (!strcmp(p, "hull1972b5")) {
1038     y[0]        = 0.0;
1039     y[1]        = 1.0;
1040     y[2]        = 1.0;
1041     RHSFunction = RHSFunction_Hull1972B5;
1042     IFunction   = IFunction_Hull1972B5;
1043     IJacobian   = IJacobian_Hull1972B5;
1044   } else if (!strcmp(p, "kulik2013i")) {
1045     t0          = 0.;
1046     y[0]        = PetscExpReal(PetscSinReal(t0 * t0));
1047     y[1]        = PetscExpReal(5. * PetscSinReal(t0 * t0));
1048     y[2]        = PetscSinReal(t0 * t0) + 1.0;
1049     y[3]        = PetscCosReal(t0 * t0);
1050     RHSFunction = RHSFunction_Kulikov2013I;
1051     RHSJacobian = RHSJacobian_Kulikov2013I;
1052     IFunction   = IFunction_Kulikov2013I;
1053     IJacobian   = IJacobian_Kulikov2013I;
1054   } else if (!strcmp(p, "hull1972c1")) {
1055     y[0]        = 1.0;
1056     RHSFunction = RHSFunction_Hull1972C1;
1057     IFunction   = IFunction_Hull1972C1;
1058     IJacobian   = IJacobian_Hull1972C1;
1059   } else if (!strcmp(p, "hull1972c2")) {
1060     y[0]        = 1.0;
1061     RHSFunction = RHSFunction_Hull1972C2;
1062     IFunction   = IFunction_Hull1972C2;
1063     IJacobian   = IJacobian_Hull1972C2;
1064   } else if ((!strcmp(p, "hull1972c3")) || (!strcmp(p, "hull1972c4"))) {
1065     y[0]        = 1.0;
1066     RHSFunction = RHSFunction_Hull1972C34;
1067     IFunction   = IFunction_Hull1972C34;
1068     IJacobian   = IJacobian_Hull1972C34;
1069   }
1070   PetscCall(PetscOptionsGetScalarArray(NULL, NULL, "-yinit", y, &N, &flg));
1071   PetscCheck((N == GetSize((const char *)s)) || !flg, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "Number of initial values %" PetscInt_FMT " does not match problem size %" PetscInt_FMT ".", N, GetSize((const char *)s));
1072   PetscCall(VecRestoreArray(Y, &y));
1073   PetscFunctionReturn(0);
1074 }
1075 
1076 /* Calculates the exact solution to problems that have one */
1077 PetscErrorCode ExactSolution(Vec Y, void *s, PetscReal t, PetscBool *flag) {
1078   char        *p = (char *)s;
1079   PetscScalar *y;
1080 
1081   PetscFunctionBeginUser;
1082   if (!strcmp(p, "hull1972a1")) {
1083     PetscCall(VecGetArray(Y, &y));
1084     y[0]  = PetscExpReal(-t);
1085     *flag = PETSC_TRUE;
1086     PetscCall(VecRestoreArray(Y, &y));
1087   } else if (!strcmp(p, "hull1972a2")) {
1088     PetscCall(VecGetArray(Y, &y));
1089     y[0]  = 1.0 / PetscSqrtReal(t + 1);
1090     *flag = PETSC_TRUE;
1091     PetscCall(VecRestoreArray(Y, &y));
1092   } else if (!strcmp(p, "hull1972a3")) {
1093     PetscCall(VecGetArray(Y, &y));
1094     y[0]  = PetscExpReal(PetscSinReal(t));
1095     *flag = PETSC_TRUE;
1096     PetscCall(VecRestoreArray(Y, &y));
1097   } else if (!strcmp(p, "hull1972a4")) {
1098     PetscCall(VecGetArray(Y, &y));
1099     y[0]  = 20.0 / (1 + 19.0 * PetscExpReal(-t / 4.0));
1100     *flag = PETSC_TRUE;
1101     PetscCall(VecRestoreArray(Y, &y));
1102   } else if (!strcmp(p, "kulik2013i")) {
1103     PetscCall(VecGetArray(Y, &y));
1104     y[0]  = PetscExpReal(PetscSinReal(t * t));
1105     y[1]  = PetscExpReal(5. * PetscSinReal(t * t));
1106     y[2]  = PetscSinReal(t * t) + 1.0;
1107     y[3]  = PetscCosReal(t * t);
1108     *flag = PETSC_TRUE;
1109     PetscCall(VecRestoreArray(Y, &y));
1110   } else {
1111     PetscCall(VecSet(Y, 0));
1112     *flag = PETSC_FALSE;
1113   }
1114   PetscFunctionReturn(0);
1115 }
1116 
1117 /* Solves the specified ODE and computes the error if exact solution is available */
1118 PetscErrorCode SolveODE(char *ptype, PetscReal dt, PetscReal tfinal, PetscInt maxiter, PetscReal *error, PetscBool *exact_flag) {
1119   TS        ts;          /* time-integrator                        */
1120   Vec       Y;           /* Solution vector                        */
1121   Vec       Yex;         /* Exact solution                         */
1122   PetscInt  N;           /* Size of the system of equations        */
1123   TSType    time_scheme; /* Type of time-integration scheme        */
1124   Mat       Jac = NULL;  /* Jacobian matrix                        */
1125   Vec       Yerr;        /* Auxiliary solution vector              */
1126   PetscReal err_norm;    /* Estimated error norm                   */
1127   PetscReal final_time;  /* Actual final time from the integrator  */
1128 
1129   PetscFunctionBeginUser;
1130   N = GetSize((const char *)&ptype[0]);
1131   PetscCheck(N >= 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_SIZ, "Illegal problem specification.");
1132   PetscCall(VecCreate(PETSC_COMM_WORLD, &Y));
1133   PetscCall(VecSetSizes(Y, N, PETSC_DECIDE));
1134   PetscCall(VecSetUp(Y));
1135   PetscCall(VecSet(Y, 0));
1136 
1137   /* Initialize the problem */
1138   PetscCall(Initialize(Y, &ptype[0]));
1139 
1140   /* Create and initialize the time-integrator                            */
1141   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
1142   /* Default time integration options                                     */
1143   PetscCall(TSSetType(ts, TSRK));
1144   PetscCall(TSSetMaxSteps(ts, maxiter));
1145   PetscCall(TSSetMaxTime(ts, tfinal));
1146   PetscCall(TSSetTimeStep(ts, dt));
1147   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
1148   /* Read command line options for time integration                       */
1149   PetscCall(TSSetFromOptions(ts));
1150   /* Set solution vector                                                  */
1151   PetscCall(TSSetSolution(ts, Y));
1152   /* Specify left/right-hand side functions                               */
1153   PetscCall(TSGetType(ts, &time_scheme));
1154 
1155   if ((!strcmp(time_scheme, TSEULER)) || (!strcmp(time_scheme, TSRK)) || (!strcmp(time_scheme, TSSSP) || (!strcmp(time_scheme, TSGLEE)))) {
1156     /* Explicit time-integration -> specify right-hand side function ydot = f(y) */
1157     PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, &ptype[0]));
1158     PetscCall(MatCreate(PETSC_COMM_WORLD, &Jac));
1159     PetscCall(MatSetSizes(Jac, PETSC_DECIDE, PETSC_DECIDE, N, N));
1160     PetscCall(MatSetFromOptions(Jac));
1161     PetscCall(MatSetUp(Jac));
1162     PetscCall(TSSetRHSJacobian(ts, Jac, Jac, RHSJacobian, &ptype[0]));
1163   } else if ((!strcmp(time_scheme, TSTHETA)) || (!strcmp(time_scheme, TSBEULER)) || (!strcmp(time_scheme, TSCN)) || (!strcmp(time_scheme, TSALPHA)) || (!strcmp(time_scheme, TSARKIMEX))) {
1164     /* Implicit time-integration -> specify left-hand side function ydot-f(y) = 0 */
1165     /* and its Jacobian function                                                 */
1166     PetscCall(TSSetIFunction(ts, NULL, IFunction, &ptype[0]));
1167     PetscCall(MatCreate(PETSC_COMM_WORLD, &Jac));
1168     PetscCall(MatSetSizes(Jac, PETSC_DECIDE, PETSC_DECIDE, N, N));
1169     PetscCall(MatSetFromOptions(Jac));
1170     PetscCall(MatSetUp(Jac));
1171     PetscCall(TSSetIJacobian(ts, Jac, Jac, IJacobian, &ptype[0]));
1172   }
1173 
1174   /* Solve */
1175   PetscCall(TSSolve(ts, Y));
1176   PetscCall(TSGetTime(ts, &final_time));
1177 
1178   /* Get the estimated error, if available */
1179   PetscCall(VecDuplicate(Y, &Yerr));
1180   PetscCall(VecZeroEntries(Yerr));
1181   PetscCall(TSGetTimeError(ts, 0, &Yerr));
1182   PetscCall(VecNorm(Yerr, NORM_2, &err_norm));
1183   PetscCall(VecDestroy(&Yerr));
1184   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Estimated Error = %e.\n", (double)err_norm));
1185 
1186   /* Exact solution */
1187   PetscCall(VecDuplicate(Y, &Yex));
1188   if (PetscAbsReal(final_time - tfinal) > 2. * PETSC_MACHINE_EPSILON) {
1189     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Note: There is a difference between the prescribed final time %g and the actual final time, %g.\n", (double)tfinal, (double)final_time));
1190   }
1191   PetscCall(ExactSolution(Yex, &ptype[0], final_time, exact_flag));
1192 
1193   /* Calculate Error */
1194   PetscCall(VecAYPX(Yex, -1.0, Y));
1195   PetscCall(VecNorm(Yex, NORM_2, error));
1196   *error = PetscSqrtReal(((*error) * (*error)) / N);
1197 
1198   /* Clean up and finalize */
1199   PetscCall(MatDestroy(&Jac));
1200   PetscCall(TSDestroy(&ts));
1201   PetscCall(VecDestroy(&Yex));
1202   PetscCall(VecDestroy(&Y));
1203 
1204   PetscFunctionReturn(0);
1205 }
1206 
1207 int main(int argc, char **argv) {
1208   char        ptype[256] = "hull1972a1"; /* Problem specification                                */
1209   PetscInt    n_refine   = 1;            /* Number of refinement levels for convergence analysis */
1210   PetscReal   refine_fac = 2.0;          /* Refinement factor for dt                             */
1211   PetscReal   dt_initial = 0.01;         /* Initial default value of dt                          */
1212   PetscReal   dt;
1213   PetscReal   tfinal  = 20.0;   /* Final time for the time-integration                  */
1214   PetscInt    maxiter = 100000; /* Maximum number of time-integration iterations        */
1215   PetscReal  *error;            /* Array to store the errors for convergence analysis   */
1216   PetscMPIInt size;             /* No of processors                                     */
1217   PetscBool   flag;             /* Flag denoting availability of exact solution         */
1218   PetscInt    r;
1219 
1220   /* Initialize program */
1221   PetscFunctionBeginUser;
1222   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
1223 
1224   /* Check if running with only 1 proc */
1225   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
1226   PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "Only for sequential runs");
1227 
1228   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "ex31", NULL);
1229   PetscCall(PetscOptionsString("-problem", "Problem specification", "<hull1972a1>", ptype, ptype, sizeof(ptype), NULL));
1230   PetscCall(PetscOptionsInt("-refinement_levels", "Number of refinement levels for convergence analysis", "<1>", n_refine, &n_refine, NULL));
1231   PetscCall(PetscOptionsReal("-refinement_factor", "Refinement factor for dt", "<2.0>", refine_fac, &refine_fac, NULL));
1232   PetscCall(PetscOptionsReal("-dt", "Time step size (for convergence analysis, initial time step)", "<0.01>", dt_initial, &dt_initial, NULL));
1233   PetscCall(PetscOptionsReal("-final_time", "Final time for the time-integration", "<20.0>", tfinal, &tfinal, NULL));
1234   PetscOptionsEnd();
1235 
1236   PetscCall(PetscMalloc1(n_refine, &error));
1237   for (r = 0, dt = dt_initial; r < n_refine; r++) {
1238     error[r] = 0;
1239     if (r > 0) dt /= refine_fac;
1240 
1241     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solving ODE \"%s\" with dt %f, final time %f and system size %" PetscInt_FMT ".\n", ptype, (double)dt, (double)tfinal, GetSize(&ptype[0])));
1242     PetscCall(SolveODE(&ptype[0], dt, tfinal, maxiter, &error[r], &flag));
1243     if (flag) {
1244       /* If exact solution available for the specified ODE */
1245       if (r > 0) {
1246         PetscReal conv_rate = (PetscLogReal(error[r]) - PetscLogReal(error[r - 1])) / (-PetscLogReal(refine_fac));
1247         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Error           = %E,\tConvergence rate = %f.\n", (double)error[r], (double)conv_rate));
1248       } else {
1249         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Error           = %E.\n", (double)error[r]));
1250       }
1251     }
1252   }
1253   PetscCall(PetscFree(error));
1254   PetscCall(PetscFinalize());
1255   return 0;
1256 }
1257 
1258 /*TEST
1259 
1260     test:
1261       suffix: 2
1262       args: -ts_type glee -final_time 5 -ts_adapt_type none
1263       timeoutfactor: 3
1264       requires: !single
1265 
1266     test:
1267       suffix: 3
1268       args: -ts_type glee -final_time 5 -ts_adapt_type glee -ts_adapt_monitor  -ts_max_steps 50  -problem hull1972a3 -ts_adapt_glee_use_local 1
1269       timeoutfactor: 3
1270       requires: !single
1271 
1272     test:
1273       suffix: 4
1274       args: -ts_type glee -final_time 5 -ts_adapt_type glee -ts_adapt_monitor  -ts_max_steps 50  -problem hull1972a3  -ts_max_reject 100 -ts_adapt_glee_use_local 0
1275       timeoutfactor: 3
1276       requires: !single !__float128
1277 
1278 TEST*/
1279