xref: /petsc/src/ts/tutorials/ex74.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 static char help[] = "Solves the constant-coefficient 1D heat equation \n\
2 with an Implicit Runge-Kutta method using MatKAIJ.                  \n\
3                                                                     \n\
4     du      d^2 u                                                   \n\
5     --  = a ----- ; 0 <= x <= 1;                                    \n\
6     dt      dx^2                                                    \n\
7                                                                     \n\
8   with periodic boundary conditions                                 \n\
9                                                                     \n\
10 2nd order central discretization in space:                          \n\
11                                                                     \n\
12    [ d^2 u ]     u_{i+1} - 2u_i + u_{i-1}                           \n\
13    [ ----- ]  =  ------------------------                           \n\
14    [ dx^2  ]i              h^2                                      \n\
15                                                                     \n\
16     i = grid index;    h = x_{i+1}-x_i (Uniform)                    \n\
17     0 <= i < n         h = 1.0/n                                    \n\
18                                                                     \n\
19 Thus,                                                               \n\
20                                                                     \n\
21    du                                                               \n\
22    --  = Ju;  J = (a/h^2) tridiagonal(1,-2,1)_n                     \n\
23    dt                                                               \n\
24                                                                     \n\
25 This example is a TS version of the KSP ex74.c tutorial.            \n";
26 
27 #include <petscts.h>
28 
29 typedef enum {
30   PHYSICS_DIFFUSION,
31   PHYSICS_ADVECTION
32 } PhysicsType;
33 const char *const PhysicsTypes[] = {"DIFFUSION", "ADVECTION", "PhysicsType", "PHYSICS_", NULL};
34 
35 typedef struct Context {
36   PetscReal   a;          /* diffusion coefficient      */
37   PetscReal   xmin, xmax; /* domain bounds              */
38   PetscInt    imax;       /* number of grid points      */
39   PhysicsType physics_type;
40 } UserContext;
41 
42 static PetscErrorCode ExactSolution(Vec, void *, PetscReal);
43 static PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *);
44 
45 int main(int argc, char **argv) {
46   TS          ts;
47   Mat         A;
48   Vec         u, uex;
49   UserContext ctxt;
50   PetscReal   err, ftime;
51 
52   PetscFunctionBeginUser;
53   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
54   /* default value */
55   ctxt.a            = 0.1;
56   ctxt.xmin         = 0.0;
57   ctxt.xmax         = 1.0;
58   ctxt.imax         = 40;
59   ctxt.physics_type = PHYSICS_DIFFUSION;
60 
61   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "IRK options", "");
62   PetscCall(PetscOptionsReal("-a", "diffusion coefficient", "<1.0>", ctxt.a, &ctxt.a, NULL));
63   PetscCall(PetscOptionsInt("-imax", "grid size", "<20>", ctxt.imax, &ctxt.imax, NULL));
64   PetscCall(PetscOptionsReal("-xmin", "xmin", "<0.0>", ctxt.xmin, &ctxt.xmin, NULL));
65   PetscCall(PetscOptionsReal("-xmax", "xmax", "<1.0>", ctxt.xmax, &ctxt.xmax, NULL));
66   PetscCall(PetscOptionsEnum("-physics_type", "Type of process to discretize", "", PhysicsTypes, (PetscEnum)ctxt.physics_type, (PetscEnum *)&ctxt.physics_type, NULL));
67   PetscOptionsEnd();
68 
69   /* allocate and initialize solution vector and exact solution */
70   PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
71   PetscCall(VecSetSizes(u, PETSC_DECIDE, ctxt.imax));
72   PetscCall(VecSetFromOptions(u));
73   PetscCall(VecDuplicate(u, &uex));
74   /* initial solution */
75   PetscCall(ExactSolution(u, &ctxt, 0.0));
76 
77   PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
78   PetscCall(MatSetType(A, MATAIJ));
79   PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, ctxt.imax, ctxt.imax));
80   PetscCall(MatSetUp(A));
81 
82   /* Create and set options for TS */
83   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
84   PetscCall(TSSetProblemType(ts, TS_LINEAR));
85   PetscCall(TSSetTimeStep(ts, 0.125));
86   PetscCall(TSSetSolution(ts, u));
87   PetscCall(TSSetMaxSteps(ts, 10));
88   PetscCall(TSSetMaxTime(ts, 1.0));
89   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
90   PetscCall(TSSetRHSFunction(ts, NULL, TSComputeRHSFunctionLinear, &ctxt));
91   PetscCall(RHSJacobian(ts, 0, u, A, A, &ctxt));
92   PetscCall(TSSetRHSJacobian(ts, A, A, TSComputeRHSJacobianConstant, &ctxt));
93   PetscCall(TSSetFromOptions(ts));
94   PetscCall(TSSolve(ts, u));
95 
96   PetscCall(TSGetSolveTime(ts, &ftime));
97   /* exact   solution */
98   PetscCall(ExactSolution(uex, &ctxt, ftime));
99 
100   /* Calculate error in final solution */
101   PetscCall(VecAYPX(uex, -1.0, u));
102   PetscCall(VecNorm(uex, NORM_2, &err));
103   err = PetscSqrtReal(err * err / ((PetscReal)ctxt.imax));
104   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "L2 norm of the numerical error = %g (time=%g)\n", (double)err, (double)ftime));
105 
106   /* Free up memory */
107   PetscCall(TSDestroy(&ts));
108   PetscCall(MatDestroy(&A));
109   PetscCall(VecDestroy(&uex));
110   PetscCall(VecDestroy(&u));
111   PetscCall(PetscFinalize());
112   return 0;
113 }
114 
115 PetscErrorCode ExactSolution(Vec u, void *c, PetscReal t) {
116   UserContext *ctxt = (UserContext *)c;
117   PetscInt     i, is, ie;
118   PetscScalar *uarr;
119   PetscReal    x, dx, a = ctxt->a, pi = PETSC_PI;
120 
121   PetscFunctionBeginUser;
122   dx = (ctxt->xmax - ctxt->xmin) / ((PetscReal)ctxt->imax);
123   PetscCall(VecGetOwnershipRange(u, &is, &ie));
124   PetscCall(VecGetArray(u, &uarr));
125   for (i = is; i < ie; i++) {
126     x = i * dx;
127     switch (ctxt->physics_type) {
128     case PHYSICS_DIFFUSION: uarr[i - is] = PetscExpScalar(-4.0 * pi * pi * a * t) * PetscSinScalar(2 * pi * x); break;
129     case PHYSICS_ADVECTION: uarr[i - is] = PetscSinScalar(2 * pi * (x - a * t)); break;
130     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for physics type %s", PhysicsTypes[ctxt->physics_type]);
131     }
132   }
133   PetscCall(VecRestoreArray(u, &uarr));
134   PetscFunctionReturn(0);
135 }
136 
137 static PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat J, Mat Jpre, void *ctx) {
138   UserContext *user = (UserContext *)ctx;
139   PetscInt     matis, matie, i;
140   PetscReal    dx, dx2;
141 
142   PetscFunctionBeginUser;
143   dx  = (user->xmax - user->xmin) / ((PetscReal)user->imax);
144   dx2 = dx * dx;
145   PetscCall(MatGetOwnershipRange(J, &matis, &matie));
146   for (i = matis; i < matie; i++) {
147     PetscScalar values[3];
148     PetscInt    col[3];
149     switch (user->physics_type) {
150     case PHYSICS_DIFFUSION:
151       values[0] = user->a * 1.0 / dx2;
152       values[1] = -user->a * 2.0 / dx2;
153       values[2] = user->a * 1.0 / dx2;
154       break;
155     case PHYSICS_ADVECTION:
156       values[0] = user->a * .5 / dx;
157       values[1] = 0.;
158       values[2] = -user->a * .5 / dx;
159       break;
160     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for physics type %s", PhysicsTypes[user->physics_type]);
161     }
162     /* periodic boundaries */
163     if (i == 0) {
164       col[0] = user->imax - 1;
165       col[1] = i;
166       col[2] = i + 1;
167     } else if (i == user->imax - 1) {
168       col[0] = i - 1;
169       col[1] = i;
170       col[2] = 0;
171     } else {
172       col[0] = i - 1;
173       col[1] = i;
174       col[2] = i + 1;
175     }
176     PetscCall(MatSetValues(J, 1, &i, 3, col, values, INSERT_VALUES));
177   }
178   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
179   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
180   PetscFunctionReturn(0);
181 }
182 
183 /*TEST
184 
185   test:
186     requires: double
187     suffix: 1
188     nsize: {{1 2}}
189     args: -ts_max_steps 5 -ts_monitor -ksp_monitor_short -pc_type pbjacobi -ksp_atol 1e-6 -ts_type irk -ts_irk_nstages 2
190 
191   test:
192     requires: double
193     suffix: 2
194     args: -ts_max_steps 5 -ts_monitor -ksp_monitor_short -pc_type pbjacobi -ksp_atol 1e-6 -ts_type irk -ts_irk_nstages 3
195 
196   testset:
197     requires: hpddm
198     args: -ts_max_steps 5 -ts_monitor -ksp_monitor_short -pc_type pbjacobi -ksp_atol 1e-4 -ts_type irk -ts_irk_nstages 3 -ksp_view_final_residual -ksp_hpddm_type gcrodr -ksp_type hpddm
199     test:
200       suffix: 3
201       requires: double
202       args: -ksp_hpddm_precision {{single double}shared output}
203     test:
204       suffix: 3_single
205       requires: single
206       args: -ksp_hpddm_precision {{single double}shared output}
207     test:
208       suffix: 3___float128
209       requires: __float128
210       output_file: output/ex74_3.out
211       args: -ksp_hpddm_precision {{double quadruple}shared output}
212 TEST*/
213