xref: /petsc/src/ts/tutorials/ex1.c (revision 3ba1676111f5c958fe6c2729b46ca4d523958bb3)
1c4762a1bSJed Brown 
2c4762a1bSJed Brown static char help[] = "Solves the time independent Bratu problem using pseudo-timestepping.";
3c4762a1bSJed Brown 
4c4762a1bSJed Brown /* ------------------------------------------------------------------------
5c4762a1bSJed Brown 
6c4762a1bSJed Brown     This code demonstrates how one may solve a nonlinear problem
7c4762a1bSJed Brown     with pseudo-timestepping. In this simple example, the pseudo-timestep
8c4762a1bSJed Brown     is the same for all grid points, i.e., this is equivalent to using
9c4762a1bSJed Brown     the backward Euler method with a variable timestep.
10c4762a1bSJed Brown 
11c4762a1bSJed Brown     Note: This example does not require pseudo-timestepping since it
12c4762a1bSJed Brown     is an easy nonlinear problem, but it is included to demonstrate how
13c4762a1bSJed Brown     the pseudo-timestepping may be done.
14c4762a1bSJed Brown 
15c4762a1bSJed Brown     See snes/tutorials/ex4.c[ex4f.F] and
16c4762a1bSJed Brown     snes/tutorials/ex5.c[ex5f.F] where the problem is described
17c4762a1bSJed Brown     and solved using Newton's method alone.
18c4762a1bSJed Brown 
19c4762a1bSJed Brown   ----------------------------------------------------------------------------- */
20c4762a1bSJed Brown /*
21c4762a1bSJed Brown     Include "petscts.h" to use the PETSc timestepping routines. Note that
22c4762a1bSJed Brown     this file automatically includes "petscsys.h" and other lower-level
23c4762a1bSJed Brown     PETSc include files.
24c4762a1bSJed Brown */
25c4762a1bSJed Brown #include <petscts.h>
26c4762a1bSJed Brown 
27c4762a1bSJed Brown /*
28c4762a1bSJed Brown   Create an application context to contain data needed by the
29c4762a1bSJed Brown   application-provided call-back routines, FormJacobian() and
30c4762a1bSJed Brown   FormFunction().
31c4762a1bSJed Brown */
32c4762a1bSJed Brown typedef struct {
33c4762a1bSJed Brown   PetscReal param; /* test problem parameter */
34c4762a1bSJed Brown   PetscInt  mx;    /* Discretization in x-direction */
35c4762a1bSJed Brown   PetscInt  my;    /* Discretization in y-direction */
36c4762a1bSJed Brown } AppCtx;
37c4762a1bSJed Brown 
38c4762a1bSJed Brown /*
39c4762a1bSJed Brown    User-defined routines
40c4762a1bSJed Brown */
41c4762a1bSJed Brown extern PetscErrorCode FormJacobian(TS, PetscReal, Vec, Mat, Mat, void *), FormFunction(TS, PetscReal, Vec, Vec, void *), FormInitialGuess(Vec, AppCtx *);
42c4762a1bSJed Brown 
43d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
44d71ae5a4SJacob Faibussowitsch {
45c4762a1bSJed Brown   TS          ts;     /* timestepping context */
46c4762a1bSJed Brown   Vec         x, r;   /* solution, residual vectors */
47c4762a1bSJed Brown   Mat         J;      /* Jacobian matrix */
48c4762a1bSJed Brown   AppCtx      user;   /* user-defined work context */
49c4762a1bSJed Brown   PetscInt    its, N; /* iterations for convergence */
50c4762a1bSJed Brown   PetscReal   param_max = 6.81, param_min = 0., dt;
51c4762a1bSJed Brown   PetscReal   ftime;
52c4762a1bSJed Brown   PetscMPIInt size;
53c4762a1bSJed Brown 
54327415f7SBarry Smith   PetscFunctionBeginUser;
559566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
569566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
573c633725SBarry Smith   PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "This is a uniprocessor example only");
58c4762a1bSJed Brown 
59c4762a1bSJed Brown   user.mx    = 4;
60c4762a1bSJed Brown   user.my    = 4;
61c4762a1bSJed Brown   user.param = 6.0;
62c4762a1bSJed Brown 
63c4762a1bSJed Brown   /*
64c4762a1bSJed Brown      Allow user to set the grid dimensions and nonlinearity parameter at run-time
65c4762a1bSJed Brown   */
66*3ba16761SJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mx", &user.mx, NULL));
67*3ba16761SJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-my", &user.my, NULL));
68c4762a1bSJed Brown   N  = user.mx * user.my;
69c4762a1bSJed Brown   dt = .5 / PetscMax(user.mx, user.my);
70*3ba16761SJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, NULL, "-param", &user.param, NULL));
713c633725SBarry Smith   PetscCheck(user.param < param_max && user.param >= param_min, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Parameter is out of range");
72c4762a1bSJed Brown 
73c4762a1bSJed Brown   /*
74c4762a1bSJed Brown       Create vectors to hold the solution and function value
75c4762a1bSJed Brown   */
769566063dSJacob Faibussowitsch   PetscCall(VecCreateSeq(PETSC_COMM_SELF, N, &x));
779566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(x, &r));
78c4762a1bSJed Brown 
79c4762a1bSJed Brown   /*
80c4762a1bSJed Brown     Create matrix to hold Jacobian. Preallocate 5 nonzeros per row
81c4762a1bSJed Brown     in the sparse matrix. Note that this is not the optimal strategy; see
82c4762a1bSJed Brown     the Performance chapter of the users manual for information on
83c4762a1bSJed Brown     preallocating memory in sparse matrices.
84c4762a1bSJed Brown   */
859566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, N, N, 5, 0, &J));
86c4762a1bSJed Brown 
87c4762a1bSJed Brown   /*
88c4762a1bSJed Brown      Create timestepper context
89c4762a1bSJed Brown   */
909566063dSJacob Faibussowitsch   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
919566063dSJacob Faibussowitsch   PetscCall(TSSetProblemType(ts, TS_NONLINEAR));
92c4762a1bSJed Brown 
93c4762a1bSJed Brown   /*
94c4762a1bSJed Brown      Tell the timestepper context where to compute solutions
95c4762a1bSJed Brown   */
969566063dSJacob Faibussowitsch   PetscCall(TSSetSolution(ts, x));
97c4762a1bSJed Brown 
98c4762a1bSJed Brown   /*
99c4762a1bSJed Brown      Provide the call-back for the nonlinear function we are
100c4762a1bSJed Brown      evaluating. Thus whenever the timestepping routines need the
101c4762a1bSJed Brown      function they will call this routine. Note the final argument
102c4762a1bSJed Brown      is the application context used by the call-back functions.
103c4762a1bSJed Brown   */
1049566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts, NULL, FormFunction, &user));
105c4762a1bSJed Brown 
106c4762a1bSJed Brown   /*
107c4762a1bSJed Brown      Set the Jacobian matrix and the function used to compute
108c4762a1bSJed Brown      Jacobians.
109c4762a1bSJed Brown   */
1109566063dSJacob Faibussowitsch   PetscCall(TSSetRHSJacobian(ts, J, J, FormJacobian, &user));
111c4762a1bSJed Brown 
112c4762a1bSJed Brown   /*
113c4762a1bSJed Brown        Form the initial guess for the problem
114c4762a1bSJed Brown   */
1159566063dSJacob Faibussowitsch   PetscCall(FormInitialGuess(x, &user));
116c4762a1bSJed Brown 
117c4762a1bSJed Brown   /*
118c4762a1bSJed Brown        This indicates that we are using pseudo timestepping to
119c4762a1bSJed Brown      find a steady state solution to the nonlinear problem.
120c4762a1bSJed Brown   */
1219566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSPSEUDO));
122c4762a1bSJed Brown 
123c4762a1bSJed Brown   /*
124c4762a1bSJed Brown        Set the initial time to start at (this is arbitrary for
125c4762a1bSJed Brown      steady state problems); and the initial timestep given above
126c4762a1bSJed Brown   */
1279566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, dt));
128c4762a1bSJed Brown 
129c4762a1bSJed Brown   /*
130c4762a1bSJed Brown       Set a large number of timesteps and final duration time
131c4762a1bSJed Brown      to insure convergence to steady state.
132c4762a1bSJed Brown   */
1339566063dSJacob Faibussowitsch   PetscCall(TSSetMaxSteps(ts, 10000));
1349566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, 1e12));
1359566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
136c4762a1bSJed Brown 
137c4762a1bSJed Brown   /*
138c4762a1bSJed Brown       Use the default strategy for increasing the timestep
139c4762a1bSJed Brown   */
1409566063dSJacob Faibussowitsch   PetscCall(TSPseudoSetTimeStep(ts, TSPseudoTimeStepDefault, 0));
141c4762a1bSJed Brown 
142c4762a1bSJed Brown   /*
143c4762a1bSJed Brown       Set any additional options from the options database. This
144c4762a1bSJed Brown      includes all options for the nonlinear and linear solvers used
145c4762a1bSJed Brown      internally the timestepping routines.
146c4762a1bSJed Brown   */
1479566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts));
148c4762a1bSJed Brown 
1499566063dSJacob Faibussowitsch   PetscCall(TSSetUp(ts));
150c4762a1bSJed Brown 
151c4762a1bSJed Brown   /*
152c4762a1bSJed Brown       Perform the solve. This is where the timestepping takes place.
153c4762a1bSJed Brown   */
1549566063dSJacob Faibussowitsch   PetscCall(TSSolve(ts, x));
1559566063dSJacob Faibussowitsch   PetscCall(TSGetSolveTime(ts, &ftime));
156c4762a1bSJed Brown 
157c4762a1bSJed Brown   /*
158c4762a1bSJed Brown       Get the number of steps
159c4762a1bSJed Brown   */
1609566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &its));
161c4762a1bSJed Brown 
16263a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of pseudo timesteps = %" PetscInt_FMT " final time %4.2e\n", its, (double)ftime));
163c4762a1bSJed Brown 
164c4762a1bSJed Brown   /*
165c4762a1bSJed Brown      Free the data structures constructed above
166c4762a1bSJed Brown   */
1679566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
1689566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&r));
1699566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&J));
1709566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
1719566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
172b122ec5aSJacob Faibussowitsch   return 0;
173c4762a1bSJed Brown }
174c4762a1bSJed Brown /* ------------------------------------------------------------------ */
175c4762a1bSJed Brown /*           Bratu (Solid Fuel Ignition) Test Problem                 */
176c4762a1bSJed Brown /* ------------------------------------------------------------------ */
177c4762a1bSJed Brown 
178c4762a1bSJed Brown /* --------------------  Form initial approximation ----------------- */
179c4762a1bSJed Brown 
180d71ae5a4SJacob Faibussowitsch PetscErrorCode FormInitialGuess(Vec X, AppCtx *user)
181d71ae5a4SJacob Faibussowitsch {
182c4762a1bSJed Brown   PetscInt     i, j, row, mx, my;
183c4762a1bSJed Brown   PetscReal    one = 1.0, lambda;
184c4762a1bSJed Brown   PetscReal    temp1, temp, hx, hy;
185c4762a1bSJed Brown   PetscScalar *x;
186c4762a1bSJed Brown 
187*3ba16761SJacob Faibussowitsch   PetscFunctionBeginUser;
188c4762a1bSJed Brown   mx     = user->mx;
189c4762a1bSJed Brown   my     = user->my;
190c4762a1bSJed Brown   lambda = user->param;
191c4762a1bSJed Brown 
192c4762a1bSJed Brown   hx = one / (PetscReal)(mx - 1);
193c4762a1bSJed Brown   hy = one / (PetscReal)(my - 1);
194c4762a1bSJed Brown 
1959566063dSJacob Faibussowitsch   PetscCall(VecGetArray(X, &x));
196c4762a1bSJed Brown   temp1 = lambda / (lambda + one);
197c4762a1bSJed Brown   for (j = 0; j < my; j++) {
198c4762a1bSJed Brown     temp = (PetscReal)(PetscMin(j, my - j - 1)) * hy;
199c4762a1bSJed Brown     for (i = 0; i < mx; i++) {
200c4762a1bSJed Brown       row = i + j * mx;
201c4762a1bSJed Brown       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
202c4762a1bSJed Brown         x[row] = 0.0;
203c4762a1bSJed Brown         continue;
204c4762a1bSJed Brown       }
205c4762a1bSJed Brown       x[row] = temp1 * PetscSqrtReal(PetscMin((PetscReal)(PetscMin(i, mx - i - 1)) * hx, temp));
206c4762a1bSJed Brown     }
207c4762a1bSJed Brown   }
2089566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(X, &x));
209*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
210c4762a1bSJed Brown }
211c4762a1bSJed Brown /* --------------------  Evaluate Function F(x) --------------------- */
212c4762a1bSJed Brown 
213d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction(TS ts, PetscReal t, Vec X, Vec F, void *ptr)
214d71ae5a4SJacob Faibussowitsch {
215c4762a1bSJed Brown   AppCtx            *user = (AppCtx *)ptr;
216c4762a1bSJed Brown   PetscInt           i, j, row, mx, my;
217c4762a1bSJed Brown   PetscReal          two = 2.0, one = 1.0, lambda;
218c4762a1bSJed Brown   PetscReal          hx, hy, hxdhy, hydhx;
219c4762a1bSJed Brown   PetscScalar        ut, ub, ul, ur, u, uxx, uyy, sc, *f;
220c4762a1bSJed Brown   const PetscScalar *x;
221c4762a1bSJed Brown 
222*3ba16761SJacob Faibussowitsch   PetscFunctionBeginUser;
223c4762a1bSJed Brown   mx     = user->mx;
224c4762a1bSJed Brown   my     = user->my;
225c4762a1bSJed Brown   lambda = user->param;
226c4762a1bSJed Brown 
227c4762a1bSJed Brown   hx    = one / (PetscReal)(mx - 1);
228c4762a1bSJed Brown   hy    = one / (PetscReal)(my - 1);
229c4762a1bSJed Brown   sc    = hx * hy;
230c4762a1bSJed Brown   hxdhy = hx / hy;
231c4762a1bSJed Brown   hydhx = hy / hx;
232c4762a1bSJed Brown 
2339566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, &x));
2349566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &f));
235c4762a1bSJed Brown   for (j = 0; j < my; j++) {
236c4762a1bSJed Brown     for (i = 0; i < mx; i++) {
237c4762a1bSJed Brown       row = i + j * mx;
238c4762a1bSJed Brown       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
239c4762a1bSJed Brown         f[row] = x[row];
240c4762a1bSJed Brown         continue;
241c4762a1bSJed Brown       }
242c4762a1bSJed Brown       u      = x[row];
243c4762a1bSJed Brown       ub     = x[row - mx];
244c4762a1bSJed Brown       ul     = x[row - 1];
245c4762a1bSJed Brown       ut     = x[row + mx];
246c4762a1bSJed Brown       ur     = x[row + 1];
247c4762a1bSJed Brown       uxx    = (-ur + two * u - ul) * hydhx;
248c4762a1bSJed Brown       uyy    = (-ut + two * u - ub) * hxdhy;
249c4762a1bSJed Brown       f[row] = -uxx + -uyy + sc * lambda * PetscExpScalar(u);
250c4762a1bSJed Brown     }
251c4762a1bSJed Brown   }
2529566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, &x));
2539566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &f));
254*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
255c4762a1bSJed Brown }
256c4762a1bSJed Brown /* --------------------  Evaluate Jacobian F'(x) -------------------- */
257c4762a1bSJed Brown 
258c4762a1bSJed Brown /*
259c4762a1bSJed Brown    Calculate the Jacobian matrix J(X,t).
260c4762a1bSJed Brown 
261c4762a1bSJed Brown    Note: We put the Jacobian in the preconditioner storage B instead of J. This
262c4762a1bSJed Brown    way we can give the -snes_mf_operator flag to check our work. This replaces
263c4762a1bSJed Brown    J with a finite difference approximation, using our analytic Jacobian B for
264c4762a1bSJed Brown    the preconditioner.
265c4762a1bSJed Brown */
266d71ae5a4SJacob Faibussowitsch PetscErrorCode FormJacobian(TS ts, PetscReal t, Vec X, Mat J, Mat B, void *ptr)
267d71ae5a4SJacob Faibussowitsch {
268c4762a1bSJed Brown   AppCtx            *user = (AppCtx *)ptr;
269c4762a1bSJed Brown   PetscInt           i, j, row, mx, my, col[5];
270c4762a1bSJed Brown   PetscScalar        two = 2.0, one = 1.0, lambda, v[5], sc;
271c4762a1bSJed Brown   const PetscScalar *x;
272c4762a1bSJed Brown   PetscReal          hx, hy, hxdhy, hydhx;
273c4762a1bSJed Brown 
274*3ba16761SJacob Faibussowitsch   PetscFunctionBeginUser;
275c4762a1bSJed Brown   mx     = user->mx;
276c4762a1bSJed Brown   my     = user->my;
277c4762a1bSJed Brown   lambda = user->param;
278c4762a1bSJed Brown 
279c4762a1bSJed Brown   hx    = 1.0 / (PetscReal)(mx - 1);
280c4762a1bSJed Brown   hy    = 1.0 / (PetscReal)(my - 1);
281c4762a1bSJed Brown   sc    = hx * hy;
282c4762a1bSJed Brown   hxdhy = hx / hy;
283c4762a1bSJed Brown   hydhx = hy / hx;
284c4762a1bSJed Brown 
2859566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X, &x));
286c4762a1bSJed Brown   for (j = 0; j < my; j++) {
287c4762a1bSJed Brown     for (i = 0; i < mx; i++) {
288c4762a1bSJed Brown       row = i + j * mx;
289c4762a1bSJed Brown       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
2909566063dSJacob Faibussowitsch         PetscCall(MatSetValues(B, 1, &row, 1, &row, &one, INSERT_VALUES));
291c4762a1bSJed Brown         continue;
292c4762a1bSJed Brown       }
2939371c9d4SSatish Balay       v[0]   = hxdhy;
2949371c9d4SSatish Balay       col[0] = row - mx;
2959371c9d4SSatish Balay       v[1]   = hydhx;
2969371c9d4SSatish Balay       col[1] = row - 1;
2979371c9d4SSatish Balay       v[2]   = -two * (hydhx + hxdhy) + sc * lambda * PetscExpScalar(x[row]);
2989371c9d4SSatish Balay       col[2] = row;
2999371c9d4SSatish Balay       v[3]   = hydhx;
3009371c9d4SSatish Balay       col[3] = row + 1;
3019371c9d4SSatish Balay       v[4]   = hxdhy;
3029371c9d4SSatish Balay       col[4] = row + mx;
3039566063dSJacob Faibussowitsch       PetscCall(MatSetValues(B, 1, &row, 5, col, v, INSERT_VALUES));
304c4762a1bSJed Brown     }
305c4762a1bSJed Brown   }
3069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X, &x));
3079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
3089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
309c4762a1bSJed Brown   if (J != B) {
3109566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
3119566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
312c4762a1bSJed Brown   }
313*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
314c4762a1bSJed Brown }
315c4762a1bSJed Brown 
316c4762a1bSJed Brown /*TEST
317c4762a1bSJed Brown 
318c4762a1bSJed Brown     test:
319c4762a1bSJed Brown       args: -ksp_gmres_cgs_refinement_type refine_always -snes_type newtonls -ts_monitor_pseudo -snes_atol 1.e-7 -ts_pseudo_frtol 1.e-5 -ts_view draw:tikz:fig.tex
320c4762a1bSJed Brown 
321c4762a1bSJed Brown     test:
322c4762a1bSJed Brown       suffix: 2
323c4762a1bSJed Brown       args: -ts_monitor_pseudo -ts_pseudo_frtol 1.e-5
324c4762a1bSJed Brown 
325c4762a1bSJed Brown TEST*/
326